C# 如何获取使用 SynchronizationContext 的任务?以及如何使用 SynchronizationContext 呢?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16916253/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:07:01  来源:igfitidea点击:

How to get a Task that uses SynchronizationContext? And how are SynchronizationContext used anyway?

c#async-awaitsynchronizationcontext

提问by Imi

I am still learning the whole Task-concept and TPL. From my current understanding, the SynchronizationContext functions (if present) are used by awaitto dispatch the Task "somewhere". On the other hand, the functions in the Taskclass do not use the context, right?

我仍在学习整个任务概念和 TPL。根据我目前的理解,SynchronizationContext 函数(如果存在)用于await在“某处”分派任务。另一方面,Task类中的函数不使用上下文,对吗?

So for example Task.Run(...)will always dispatch the action on an worker thread of the thread pool and ignore the SynchronizationContext.Currentcompletely. await Foobar()would use the context to execute the generated task after the await?

因此,例如Task.Run(...)将始终在线程池的工作线程上分派动作并SynchronizationContext.Current完全忽略。await Foobar()会在await?之后使用上下文来执行生成的任务。

If that is true, my question is: How can I obtain a Task, that actually runs an action but is dispatched using SynchronizationContext.Current.Send/Post?

如果这是真的,我的问题是:我怎样才能获得一个Task,它实际上运行一个动作但使用 调度SynchronizationContext.Current.Send/Post

And can anyone recommend a good introduction into SynchronizationContext, especially when and how they are used by the rest of the framework? The MSDNseems to be very quiet about the class. The top Google hits (hereand here) seem to be tailored to Windows Forms dispatching only. Stephen Cleary wrote an articlewhich is nice to learn what contexts already exist and how they work, but I lack understanding of where and when they are actually used.

任何人都可以推荐一个很好的介绍SynchronizationContext,尤其是框架的其余部分何时以及如何使用它们?在MSDN似乎很沉默的类。Google 的热门点击(此处此处)似乎仅针对 Windows 窗体调度量身定制。Stephen Cleary 写了一篇文章,很好地了解了哪些上下文已经存在以及它们是如何工作的,但我对它们的实际使用地点和时间缺乏了解。

回答by Dennis

How can I obtain a Task, that actually runs an action but is dispatched using SynchronizationContext.Current.Send/Post?

我怎样才能获得一个任务,它实际上运行一个动作但使用 SynchronizationContext.Current.Send/Post 调度?

Use special task scheduler:

使用特殊任务调度程序:

Task.Factory.StartNew(
    () => {}, // this will use current synchronization context
    CancellationToken.None, 
    TaskCreationOptions.None, 
    TaskScheduler.FromCurrentSynchronizationContext());

And can anyone recommend a good introduction into SynchronizationContext

任何人都可以推荐对 SynchronizationContext 的很好的介绍

Look at the article It's All About the SynchronizationContextby Stephen Cleary.

查看Stephen Cleary撰写的文章It's All About the SynchronizationContext

回答by Stephen Cleary

As you're learning this, it's important to point out that Taskas used by the TPLis quite different than Taskas used by async/await, even though they're the same type. For example, TPL commonly uses parent/child tasks, but async/awaitdoes not.

在学习这一点时,重要的是要指出TaskTPLTask使用的与 async/await 使用的完全不同,即使它们是相同的类型。例如,TPL 通常使用父/子任务,但async/await不使用。

TPL uses task schedulers to execute its tasks. As Dennis pointed out, TaskScheduler.FromCurrentSynchronizationContextwill give you a task scheduler that uses Poston the current SynchronizationContextto execute its task.

TPL 使用任务调度程序来执行其任务。正如丹尼斯指出的那样,TaskScheduler.FromCurrentSynchronizationContext将为您提供一个任务调度程序,用于Post在当前SynchronizationContext执行其任务。

async/awaitusually does not use task schedulers. I have an introductory async/awaitposton my blog that includes context information, and I also mention it briefly in my MSDN article(it's easy to overlook, though). Essentially, when an asyncmethod suspends at an await, by default it will capture the current SynchronizationContext(unless it is null, in which case it will capture the current TaskScheduler). When the asyncmethod resumes, it resumes executing in that context.

async/await通常不使用任务调度程序。我在我的博客上有一篇介绍async/await帖子,其中包含上下文信息,我还在我的MSDN 文章中简要提到了它(不过很容易被忽略)。本质上,当一个async方法在 挂起时await,默认情况下它将捕获当前SynchronizationContext(除非它是null,在这种情况下它将捕获当前TaskScheduler)。当该async方法恢复时,它会恢复在该上下文中执行。

Dennis pointed out the TPL way of scheduling a task to the current SynchronizationContext, but in async/awaitworld, that approach isn't necessary. Rather, you can explicitly schedule tasks to the thread pool via Task.Run:

Dennis 指出了将任务调度到当前的 TPL 方式SynchronizationContext,但在async/await世界中,这种方法不是必需的。相反,您可以通过Task.Run以下方式将任务显式安排到线程池:

async Task MyMethodAsync()
{
  // Whee, on a SynchronizationContext here!
  await Task.Run(() => { }); // Ooo, on the thread pool!
  // Back on the SynchronizationContext ...
  //  ... automagically!
}

I wrote my SynchronizationContextarticle precisely because the MSDN docs were so lacking. I have a little more information on my blog, but all the important bits are in the MSDN article. Many types use AsyncOperationrather than SynchronizationContextdirectly; the best documentation for this is buried under the EAP docs (section "Threading and Context"). But I should also point out that EAP is effectively obsolete due to async/await, so I wouldn't write code using AsyncOperation(or SynchronizationContext) - unless I was actually writing my ownSynchronizationContext.

我写我的SynchronizationContext文章正是因为 MSDN 文档太缺乏了。我的博客上更多信息,但所有重要信息都在 MSDN 文章中。许多类型使用AsyncOperation而不是SynchronizationContext直接;最好的文档隐藏在 EAP 文档下(“线程和上下文”部分)。但我还应该指出,由于async/ await,EAP 实际上已经过时了,所以我不会使用AsyncOperation(或SynchronizationContext)编写代码- 除非我实际上是在编写自己的SynchronizationContext.