电脑桌面
添加蚂蚁七词文库到电脑桌面
安装后可以在桌面快捷访问

.NET Core多线程通关 (2) 异步

来源:金蝶云社区作者:金蝶2024-09-165

.NET Core多线程通关 (2) 异步

大家好

去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的《.NET 5多线程编程实战》课程,我将复习的知识进行了总结形成本专题。

本篇,我们来复习一下异步的相关知识点,预计阅读时间10分钟。

理解异步的本质

(1)异步是什么?
举个例子,在高峰期去餐厅吃饭,会先排队拿个小票,然后去逛一下玩玩,等到排到时会被通知就餐,这时再回到餐厅就可以点餐了。
同步示意图:
图片
异步示意图:
图片
(2)同步有什么弊端

时间片切换成本高!

    • CPU密集型操作:编码解码、图形计算、正则表达式等

    • IO密集型操作:和硬件打交道,和DB打交道等

    • 线程太多的烦恼/代价:

      • 新开Thread是有开销的(时间、空间)

      • GC回收会冻结所有线程寻找引用根(gcroot)

      程序有可能会卡死!

    • Thread会和网络驱动程序打交道(外网络地址)

    • ThreadPool中的WorkQueue任务(4000+)得不到处理

    • 异步:async/await

(3)C#如何使用异步?

ThreadPool线程池分类:
    • workThread:

      • 适用于CPU密集型,在WinDbg中标签为 ThreadPool Worker

    • IOThread:

      • 适用于IO密集型,在WinDbg中标签为 ThreadPool Completion Port

HttpClient案例演示:
在下面的代码中GetContentLengthAsync异步方法中的线程就用的IOThread,可以通过WinDbg验证。

























namespace ConsoleApp3{    class Program    {        static void Main(string[] args)        {            GetContentLengthAsync("http://cnblogs.com");
           Console.WriteLine($"主线程:{Environment.CurrentManagedThreadId}, 准备退出!");            Console.ReadLine();        }
       static async Task<int> GetContentLengthAsync(string url)        {            using (HttpClient client = new HttpClient())            {                var content = await client.GetStringAsync(url);
               Console.WriteLine($"当前线程:{Environment.CurrentManagedThreadId}, content={content.Length}");
               return content.Length;            }        }    }}


异步的底层:IO完成端口
(1)理解IO完成端口
异步的核心:callback机制
IO完成端口:这是一个Windows内核对象,我们常称之为IOCP。IOCP是一个异步I/O的Windows API,它可以高效地将I/O事件通知给应用程序,类似于Linux中的Epoll。因此,.NET Framework是基于IOCP来实现的异步,而.NET Core则增加了基于epoll来实现异步,因为它要支持跨平台而不只是Windows。
SafeHandle:文件句柄、网络句柄...
核心步骤:
  • 初始化时将SafeHandle、ThreadPool与IO完成端口进行绑定(比如:FileStream在Init时)

  • (主线程)创建IO完成端口:CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, IntPtr CompletionKey, uint NumberOfConcurrentThreads)

  • (主线程)将消息塞到IO完成端口的Queue队列:PostQueuedCompletionStatus

  • (子线程)从IO完成端口的Queue队列中获取消息:GetQueuedCompletionStatus

图片
(2)实现一个简单的IO完成端口
自定义一个IOCP类,代码如下:













public class IOCP{    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]    public static extern SafeFileHandle CreateIoCompletionPort(IntPtr FileHandle, IntPtr ExistingCompletionPort, IntPtr CompletionKey, uint NumberOfConcurrentThreads);
   [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]    public static extern bool GetQueuedCompletionStatus(SafeFileHandle CompletionPort,        out uint lpNumberOfBytesTransferred, out IntPtr lpCompletionKey,        out IntPtr lpOverlapped, uint dwMilliseconds);
   [DllImport("Kernel32", CharSet = CharSet.Auto)]    public static extern bool PostQueuedCompletionStatus(SafeFileHandle CompletionPort, uint dwNumberOfBytesTransferred, IntPtr dwCompletionKey, IntPtr lpOverlapped);}
调用端代码如下:





























// 1. 创建IO完成端口var safehandle = IOCP.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, IntPtr.Zero, 1);
var thread = new Thread(() =>{    Console.WriteLine($"工作线程: {Environment.CurrentManagedThreadId} 开始获取数据...");    while (true)    {        // 3. get数据        IOCP.GetQueuedCompletionStatus(safehandle, out var ipn, out var ipc, out var lop, int.MaxValue);
       var receiveData = Convert.ToString(GCHandle.FromIntPtr(lop).Target);
       Console.WriteLine($"工作线程: {Environment.CurrentManagedThreadId} 获取数据成功!{receiveData}");
       Thread.Sleep(1000);    }});
thread.Start();
// 2. post 数据var data = (IntPtr)GCHandle.Alloc("hello world");
IOCP.PostQueuedCompletionStatus(safehandle, 4096, IntPtr.Zero, data);
Console.WriteLine($"主线程: {Environment.CurrentManagedThreadId} 塞入数据成功!");
Console.ReadLine();


加深对异步的理解
我们都知道 ContinueWith 主要起 延续任务的作用,写起来十分繁琐!
.NET 4.5推出了语法糖async/awai

.NET Core多线程通关 (2) 异步

大家好去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的《.NET 5多线程编程实战》课程,我将复习的知识进行了...
点击下载文档文档为doc格式

声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。

已经是第一篇
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息
QQ群
  • 答案:my7c点击这里加入QQ群
支持邮箱
微信
  • 微信