await调用异步之后线程ID是否与调用异步之前线程ID一致(实战篇)

17 篇文章 1 订阅
4 篇文章 0 订阅

https://www.cnblogs.com/sjyforg/p/3949029.html
看到大佬的文章,小弟来测试下

1.winform应用程序

   private void button94_Click(object sender, EventArgs e)
    {
        TestAsync();
        
    }

    private async void TestAsync()
    {
           Console.WriteLine($"主线程调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");
        await Test();

   Console.WriteLine($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");
    }

    private static Logger logger = LogManager.GetCurrentClassLogger();
 
    private async Task Test()
    {
        await GetHoliday("2021-01");
     
    }

    private async Task GetHoliday(string date)
    {
        WebClient client = new WebClient();
        client.Encoding = Encoding.UTF8;
        var url = $"https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={date}&resource_id=6018";
        var jsondata =await client.DownloadStringTaskAsync(url);
    }

输出

主线程调用异步之前ID1执行
异步后的线程ID1同步上下文:System.Windows.Forms.WindowsFormsSynchronizationContext开始执行

可以看出:调用之前ID为1,调用以后线程ID为1,同步上下文为 System.Windows.Forms.WindowsFormsSynchronizationContext.

经过多次测试:调用前后线程ID一样。

2.控制台程序

static void Main(string[] args)
{
    TestAsync();
    Console.ReadKey();
}

private static async void TestAsync()
{
    Console.WriteLine($"调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");

    await Test();

    Console.WriteLine($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");
}

private static Logger logger = LogManager.GetCurrentClassLogger();

private static async Task Test()
{
    try
    {
        await GetHoliday("2021-01");
        
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}

private static async Task GetHoliday(string date)
{
    WebClient client = new WebClient();
    client.Encoding = Encoding.UTF8;
    var url = $"https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query={date}&resource_id=6018";
    var jsondata = await client.DownloadStringTaskAsync(url);
}

输出日志:
在这里插入图片描述
可以看出:调用之前ID为1,调用以后线程ID为11,同步上下文为 null.

经过多次测试:调用前后线程ID不一样。

3.Asp.net WebApi

public async Task<string> getPATData([FromUri]PATQuery patQuery)
{
    try
    {
        Logs.Info($"主线程调用异步之前ID{Thread.CurrentThread.ManagedThreadId}执行");

        var data = new
        {
            list = await patService.GetPAT(patQuery),
            total = patQuery.records,
        };

        Logs.Info($"异步后的线程ID{Thread.CurrentThread.ManagedThreadId}同步上下文:{SynchronizationContext.Current?.ToString()}开始执行");

        return data.ToJson();
    }
    catch (Exception e)
    {
        Logs.LogWriter(e.GetOriginalException());
    }
    return string.Empty;
}

输出日志:

2022-03-05 14:07:23.2669 INFO 主线程调用异步之前ID12执行
2022-03-05 14:07:24.0974 INFO 异步后的线程ID11同步上下文:System.Web.LegacyAspNetSynchronizationContext开始执行
2022-03-05 14:07:24.6551 INFO 主线程调用异步之前ID9执行
2022-03-05 14:07:25.4546 INFO 异步后的线程ID9同步上下文:System.Web.LegacyAspNetSynchronizationContext开始执行

可以看出:

第一次调用之前ID为12,调用以后线程ID为11,同步上下文为 System.Web.LegacyAspNetSynchronizationContext

第二次调用之前ID为9,调用以后线程ID为9,同步上下文为 System.Web.LegacyAspNetSynchronizationContext

经过多次测试:调用前后线程ID可能一样可能不一样。

结论:

同步上下文(SynchronizationContext)
“同步上下文是一种可以将工作单元排队到上下文(主要是不同的线程)的方法。 它的作用通俗来讲就是实现线程之间通讯的。

在99.9%的使用场景中,SynchronizationContext仅仅被当作一个提供虚(virtual)Post方法的类,
该方法可以接收一个委托,然后异步执行它。虽
然SynchronizationContext还有许多其他的虚成员,
但是很少使用它们,而且和我们今天的内容无关,就不说了。
Post方法的基础实现就仅仅是调用一下ThreadPool.QueueUserWorkItem,
将接收的委托加入线程池队列去异步执行。
另外,派生类可以选择重写(override)Post方法,让委托在更加合适的位置和时间去执行。

例如,WinForm有一个派生自SynchronizationContext的类,重写了Post方法,
内部执行Control.BeginInvoke,
这样,调用该Post方法就会在该控件的UI线程上执行接收的委托。
WinForm依赖Win32的消息处理机制,并在UI线程上运行“消息循环”,
该线程就是简单的等待新消息到达,然后去处理。
这些消息可能是鼠标移动和点击、键盘输入、系统事件、可供调用的委托等。
所以,只需要将委托传递给SynchronizationContext实例的Post方法,就可以在控件的UI线程中执行。
和WinForm一样,WPF也有一个派生自SynchronizationContext的类,重写了Post方法,
通过Dispatcher.BeginInvoke将接收的委托封送到UI线程。
与WinForm通过控件管理不同的是,WPF是由Dispatcher管理的。

ASPNET同步上下文

AspNetSynchronizationContext
命名空间:System.Web.dll:System.Web [internal class]

实现:

ASP.NET 同步上下文在执行页面代码时安装在线程池线程上。当委托排队到捕获的AspNetSynchronizationContext时,它将还原原始页面的标识和区域性,然后直接执行委托。即使通过调用Post将其“异步”排队,也可以直接调用该委托。
从概念上讲,AspNetSynchronizationContext的上下文很复杂。在异步页的生存期内,上下文仅从ASP.NET线程池中的一个线程开始。启动异步请求后,上下文不包含任何线程。随着异步请求的完成,执行其完成例程的线程池线程将进入上下文。这些线程可能是发起请求的线程,但更有可能是操作完成时空闲的任何线程。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值