【发布时间】:2018-08-23 04:18:03
【问题描述】:
我见过很多例子,其中长时间运行的代码是从事件处理程序异步执行的。例如,这是 WPF 中按钮单击的事件处理程序:
public async void Button_Click(object sender, EventArgs e)
{
await Task.Run(() => DoWork());
}
private int DoWork()
{
for (int i = 0; i < 10000000; i++) { }
return 42;
}
如果DoWork 更复杂,比如写入数据库,那么多次单击按钮可能会导致多个线程同时尝试写入数据库。
如果不是有许多这样的Task.Run 调用,而是为所有非 UI 工作创建一个新的 Thread 会怎么样。任务可以使用BlockingCollection 之类的东西在这个线程上排队。
因为这个线程与 UI 线程是分开的,所以 UI 仍然是响应式的,并且多次单击按钮会将任务(按顺序)调度到同一个线程,从而避免并发问题。
这是个好主意吗?
【问题讨论】:
-
如果您想避免多次单击,请禁用该按钮,直到任务完成。我会避免滚动我自己的任务系统。
-
如果它是 IO 绑定的工作,比如与数据库交谈,它根本不应该使用
Task.Run,只是 async/await 一直调用。如果它是 CPU 密集型工作或 IO 不公开异步方法,您只需要启动一个线程。 -
我支持@RonBeyer:为什么要允许用户进行多次点击而不等待上一次点击“结果”?它是应用程序及其用户的价值吗?大多数时候,事实并非如此。但这实际上取决于您的情况
-
为什么要这样做?您希望从您提议的所有工作中获得什么?
-
@Servy 我希望在处理 UI 事件时获得一些一致性。例如,可能有一个类是所有要完成的非 UI 代码的“入口点”(并在其自己的线程上执行)。这将使新开发人员更难在 UI 线程上意外运行非 UI 代码。我也希望得到这样的想法,即无论正在完成的工作如何,UI都会做出响应——它可能很长,也可能很短——关键是我什至不必担心关于它:这一切都在自己的线程上完成。
标签: c# wpf multithreading asynchronous async-await