异步等待方法会在等待点阻塞UI

3

这是我的按钮事件:

private async void btnTarget_Click(object sender, EventArgs e)
{
    using (DataBaseDataContext db = new DataBaseDataContext())
    {
        targtGirdView.DataSource = await Task.Run(() =>
        {
            return heavyLinqToSQLQuery;
        });
    }
}

对于我的GridView数据源,我有一次繁重的数据库事务,我把它放在了一个await节里。但是此时,UI将会被阻塞,我不知道原因在哪里。问题出在哪里?


1
如果你有一个数据库查询,那么为什么要启动一个新线程(即Task.Run)?使用你的数据库提供程序的异步方法...除非这是Oracle,否则就算了。 - Kenneth K.
1
抱歉,无法重现此问题。可能是因为您尝试将太多的项目填充到“targtGirdView”中,控件的绘制需要太长时间。您是否尝试过不分配“targtGirdView.DataSource =”来运行程序? - Mong Zhu
1
我倾向于同意@MongZhu的看法,这似乎与渲染有关,而不是数据查询。 - Dmytro Mukalov
嗯...真奇怪。反应式扩展和LINQ.Async或许可以帮到他。也许。 - Dmitriy
Dmytro,通过将=分成两部分进行检查很容易。我认为作者已经尝试过这样做,并通过这种分割定位了问题... - Dmitriy
显示剩余2条评论
2个回答

3
你的LINQ查询应该是异步的。代码应该类似于:
private async void btnTarget_Click(object sender, EventArgs e)
{
    using (DataBaseDataContext db = new DataBaseDataContext())
    {
        targtGirdView.DataSource = await heavyLinqToSQLQuery.ToListAsync();
    }
}

3
虽然在这种情况下使用await是最好的方法,但看到为什么UI线程会在await点被阻塞的解释将会很棒 :) - Yeldar Kurmangaliyev
@the_joric 我无法将LINQ查询变为异步,因为它包含多个连接,在“select new”中我从数据库中获取一些图像,然后调整它们的大小再进行分配。 - Inside Man
尝试使用TaskCreationOptions.LongRunning来启动您的任务。 - Dmitriy
这仍然将(第一个)枚举留给了DataGrid内部。我不认为这解决了主要问题。虽然这是一种“更好的做法”。 - H H

2
我通过在LINQ查询末尾添加.ToList();解决了我的问题:"最初的回答"。
private async void btnTarget_Click(object sender, EventArgs e)
{
    using (DataBaseDataContext db = new DataBaseDataContext())
    {
        targtGirdView.DataSource = await Task.Run(() =>
        {
            return heavyLinqToSQLQuery.ToList();
        });
    }
}

但我不知道为什么它现在可以正确运行而不会阻塞用户界面。这与懒加载有关吗?

最初的回答:


3
没问题,这是正确的解决方案。你甚至不需要使用 Task.Run()。尝试使用.DataSource = await qyery.ToListAsync() - H H
2
枚举查询是耗费时间的。在您的第一个解决方案中,这是在GridView内部完成的,在分配DataSource之后。 - H H
如果你一开始就提供了查询方法,我们可能已经解决了这个问题。 - Mong Zhu
1
您的ToList调用实际上执行了查询。这被称为延迟执行。并且在数据源分配时,它是在UI线程上完成的。 - Mong Zhu
2
当查询时间很长(> = 1秒)时,使用 Task.Run 可能是值得的。但请确保将 using(db) {} 放在内部,因为 DbContext 不是线程安全的。 - H H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接