WebClient在哪些线程上引发其事件?

我找不到任何指定WebClient引发其事件的线程的文档。 我运行了一些测试并确定了以下内容:

  • 如果从UI线程调用(比如从事件处理程序调用),则将在该线程上执行事件处理程序。 作为测试,我在调用OpenReadAsync后添加了一个无限循环。 从未调用过事件处理程序。

  • 如果没有UI线程,就像在控制台应用程序中那样,事件处理程序将在线程池线程上执行。 在这种情况下,如果我想在应用程序的其余部分提供一些结果,我将不得不注意线程问题。

这种行为是否记录在何处? 我一无所获。

我有关于C#的新异步function的基本相同的问题 – 最终,必须执行异步代码。 当没有UI线程时,它还会产生一个线程池线程吗? 那反过来又需要线程安全代码吗?

我觉得我在这里遗漏了一些东西 – 我只能找到很少的相关信息,但这对我来说似乎很重要。

对于WebClient ,我还没有发现它的文档记录,但是看到了与你相同的行为。 本质上,这可以被描述为“如果在启动调用时存在活动的同步上下文,则使用它 – 否则使用线程池”。

对于C#5中的异步行为,它取决于你正在等待的任何内容的实现…但我相信Task等待者将使用TaskScheduler.Current来安排延续 – 这意味着你会看到相同的某种行为。 (它不一定只是设置任务调度程序的UI线程,但这是最明显的例子。)

当使用线程池线程时,它仍然应该是线程安全的 – 该方法一次只在一个线程中执行,我相信任务并行库执行所有必需的内存屏障。

如果您对异步如何在幕后挂起感兴趣,您可能需要阅读我的Eduasync博客系列 。

WebClient类实现基于事件的异步模式 。 该模式在框架设计指南中有详细描述,但MSDN还提供了一些如何实现的提示:

模式的实现者使用AsyncOperationManager为每个异步操作创建AsyncOperation ,并使用AsyncOperation.Post方法引发事件。 Post方法在SynchronizationContext上执行传递的回调,该回调在创建AsyncOperation时是当前的。

WinForms或WPF应用程序中的默认SynchronizationContext是UI线程,或者在Console应用程序中为null 。 在后一种情况下, WebClient类显然选择在ThreadPool线程中引发事件,但这是一个实现细节。