C# 如何禁止ExecutionContext捕获当前SynchronizationContext?
我的问题是由以下一个例子提出的: 下面是我的心智模型告诉我的,这个代码会发生什么。A. 用户单击按钮1,导致UI框架调用按钮1\u单击 在UI线程上。然后,代码启动一个工作项以在 线程池(通过Task.Run)。该工作项开始一些下载工作 并异步等待它完成。后续工作项 然后在线程池上对 下载的结果,并返回结果,导致 正在等待UI线程完成。此时,用户界面 线程处理此按钮单击方法的其余部分,存储 将计算结果输入button1的文本属性 如果SynchronizationContext不作为一部分流动,我的期望是有效的 执行上下文。但是,如果它真的流了,我会非常难过 失望。Task.Run在调用时捕获ExecutionContext,并且 使用它运行传递给它的委托。这意味着用户界面 调用Task.Run时当前的SynchronizationContext 将流入任务,并且在调用时是当前的 下载Async并等待生成的任务。那就意味着 等待将看到当前SynchronizationContext并发布 异步方法的剩余部分作为在 用户界面线程。这意味着我的计算方法很可能是 在UI线程上运行,而不是在线程池上运行,导致 我的应用程序的响应问题 让我们用以下例子来代替本文中的例子:C# 如何禁止ExecutionContext捕获当前SynchronizationContext?,c#,.net,async-await,synchronizationcontext,C#,.net,Async Await,Synchronizationcontext,我的问题是由以下一个例子提出的: 下面是我的心智模型告诉我的,这个代码会发生什么。A. 用户单击按钮1,导致UI框架调用按钮1\u单击 在UI线程上。然后,代码启动一个工作项以在 线程池(通过Task.Run)。该工作项开始一些下载工作 并异步等待它完成。后续工作项 然后在线程池上对 下载的结果,并返回结果,导致 正在等待UI线程完成。此时,用户界面 线程处理此按钮单击方法的其余部分,存储 将计算结果输入button1的文本属性 如果SynchronizationContext不作为一部分流动,
private void button1_Click(object sender, EventArgs e) {
button1.Text = await DownloadAndComputeAsync();
}
// Can't be changed
private async Task<string> DownloadAndComputeAsync() {
return await Task.Run(async delegate
{
string data = await DownloadAsync();
return Compute(data);
});
}
用例
我不知道我会想要/需要使用它,但在阅读了我在顶部链接的文章后,我可以想到一些可能有用的地方
ConfigureAwait(false)
,并且最终在UI线程上完成了大量工作。诚然,如果可能的话,我可能会停止使用图书馆ConfigureAwait(false)
,除非您知道需要返回到当前上下文。这样做的缺点是ConfigureAwait(false)
非常难看,并且会对代码可读性产生负面影响(imo)ConfigureAwait(false)
,但在所有内部代码中注意是否可以从UI上下文等使用给定的异步方法,并仅在绝对需要时使用ConfigureAwait(false)
。这似乎不太理想,因为这意味着类必须知道它们的异步方法是否可能被调用,例如UI上下文ConfigureAwait(false)
在UI上下文中调用它。这样做的好处是,所有内部非UI代码不需要使用ConfigureAwait(false)
,即使它是从事件处理程序调用的,并且所有上下文感知代码仅限于事件处理程序中的UI代码
首先;这里不要使用异步委托。您不必要地使代码复杂化了 当您有一个已经异步的操作想要得到结果时,
等待它。如果您必须执行CPU受限的工作,则在任务中运行该工作。运行调用并等待以获得结果
private void button1_Click(object sender, EventArgs e)
{
string data = await DownloadAsync();
button1.Text = await Task.Run(() => Compute(data));
}
这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果
现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个任务中都不是UI上下文。请运行委托),但要理解代码或查看它在做什么要困难得多。首先;这里不要使用异步委托。您不必要地使代码复杂化了
当您有一个已经异步的操作想要得到结果时,等待它。如果您必须执行CPU受限的工作,则在任务中运行该工作。运行调用并等待以获得结果
private void button1_Click(object sender, EventArgs e)
{
string data = await DownloadAsync();
button1.Text = await Task.Run(() => Compute(data));
}
这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果
现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个任务中都不是UI上下文。请运行委托),但要理解代码或查看它在做什么要困难得多。首先;这里不要使用异步委托。您不必要地使代码复杂化了
当您有一个已经异步的操作想要得到结果时,等待它。如果您必须执行CPU受限的工作,则在任务中运行该工作。运行调用并等待以获得结果
private void button1_Click(object sender, EventArgs e)
{
string data = await DownloadAsync();
button1.Text = await Task.Run(() => Compute(data));
}
这里很清楚发生了什么。获取异步操作的结果,使用它在非UI线程中执行一些CPU绑定的工作,然后在UI上下文中使用该结果
现在,说到这里,我希望您的代码实际上能够正常工作(假设当前上下文在整个任务中都不是UI上下文。运行委托),但是理解代码或查看它是什么要困难得多