Key*_*red 6 c# console-application synchronizationcontext async-await
我正在尝试更多地了解它SynchronizationContext,所以我制作了这个简单的控制台应用程序:
private static void Main()
{
var sc = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(sc);
DoSomething().Wait();
}
private static async Task DoSomething()
{
Console.WriteLine(SynchronizationContext.Current != null); // true
await Task.Delay(3000);
Console.WriteLine(SynchronizationContext.Current != null); // false! why ?
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,await操作员会捕获当前的信息SynchronizationContext然后将其余的异步方法发布到它.
但是,在我的应用程序中,之后SynchronizationContext.Current为null await.这是为什么 ?
编辑:
即使我自己使用SynchronizationContext它也不会被捕获,尽管它的Post功能被调用.这是我的SC:
public class MySC : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
base.Post(d, state);
Console.WriteLine("Posted");
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我使用它的方式:
var sc = new MySC();
SynchronizationContext.SetSynchronizationContext(sc);
Run Code Online (Sandbox Code Playgroud)
谢谢!
Han*_*ant 14
"捕获"这个词太不透明,听起来太像是框架所应该的东西.误导,因为它通常在使用默认SynchronizationContext实现之一的程序中执行.就像你在Winforms应用程序中获得的那个.但是当你自己编写代码时,框架就不再有用了,而你的工作就变成了你的工作.
async/await plumbing为上下文提供了在特定线程上运行continuation(await之后的代码)的机会.这听起来像是一件微不足道的事情,因为你之前经常这样做,但事实上这很困难.不可能随意中断该线程正在执行的代码,这将导致可怕的重入错误.线程必须提供帮助,它需要解决标准的生产者 - 消费者问题.采用线程安全队列和清空该队列的循环,处理调用请求.重写的Post和Send方法的工作是向队列添加请求,线程的工作是使用循环来清空它并执行请求.
Winforms,WPF或UWP应用程序的主线程有这样一个循环,它由Application.Run()执行.使用相应的SynchronizationContext,它知道如何使用调用请求来提供它,分别是WindowsFormsSynchronizationContext,DispatcherSynchronizationContext和WinRTSynchronizationContext.ASP.NET也可以这样做,使用AspNetSynchronizationContext.全部由框架提供并由类库管道自动安装.它们在构造函数中捕获同步上下文,并在Post和Send方法中使用Begin/Invoke.
当您编写自己的SynchronizationContext时,您现在必须处理这些细节.在您的代码段中,您没有覆盖Post和Send,而是继承了基本方法.他们什么都不知道,只能在任意线程池线程上执行请求.因此,在该线程上,SynchronizationContext.Current现在为null,线程池线程不知道请求来自何处.
创建自己的并不困难,ConcurrentQueue和代理帮助减少了很多代码.很多程序员都这样做了,这个库经常被引用.但是需要付出沉重的代价,调度程序循环从根本上改变了控制台模式应用程序的行为方式.它阻塞线程直到循环结束.就像Application.Run()一样.
您需要一种非常不同的编程风格,您可以从GUI应用程序中熟悉这种风格.代码不能花费太长时间,因为它会调度调度程序循环,从而阻止调度请求被调度.在用户界面变得反应迟钝的GUI应用程序中,在您的示例代码中,您会注意到您的方法很难完成,因为延续无法运行一段时间.你需要一个工作线程来分解慢速代码,没有免费的午餐.
值得注意的是为什么这个东西存在.GUI应用程序存在严重问题,它们的类库从不是线程安全的,并且使用lock其中任何一个都无法使其安全.正确使用它们的唯一方法是从同一个线程进行所有调用.如果不是,则返回InvalidOperationException.他们的调度程序循环可以帮助您执行此操作,为Begin/Invoke和async/await提供支持.控制台没有这个问题,任何线程都可以向控制台写入内容并且锁可以帮助防止它们的输出混合.因此,控制台应用程序不需要自定义SynchronizationContext.因人而异.
| 归档时间: |
|
| 查看次数: |
515 次 |
| 最近记录: |