C# 线程学习--Async
-
什么是进程?
当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。
而一个进程又是由多个线程所组成的。 -
什么是线程?
线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。 -
什么是多线程?
多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。 -
多线程的好处:
可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。 -
多线程的不利方面:
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要CPU时间跟踪线程;
线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;
线程太多会导致控制太复杂,最终可能造成很多Bug;
进程 线程 多线程 计算机概念 进程:一个程序运行时,占用的全部计算资源的总和 线程:程序执行流的最小单位;任何操作都是由线程完成的; 线程是依托于进程存在的,一个进程可以包含多个线程; 线程也可以有自己的计算资源 多线程:多个执行流同时运行 1 CPU太快了,分时间片--上下文切换(加载环境--计算--保存环境) 微观角度,一个核同一时刻只能执行一个线程;宏观的来说是多线程并发 2 多CPU多核 可以独立工作 4核8线程--核是物理的核 线程是指虚拟核
-
同步
#region ASync /// <summary> /// 同步方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSync_Click(object sender, EventArgs e) { Console.WriteLine($"****************btnSync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); int j = 3; int k = 5; int m = j + k; for (int i = 0; i < 5; i++) { string name = string.Format($"btnSync_Click_{i}"); this.DoSomethingLong(name); } Console.WriteLine($"****************btnSync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); } #endregion
#region Private Method /// <summary> /// 一个比较耗时耗资源的私有方法 /// </summary> /// <param name="name"></param> private void DoSomethingLong(string name) { Console.WriteLine($"****************DoSomethingLong {name} Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); long lResult = 0; for (int i = 0; i < 1000000000; i++) { lResult += i; } //Thread.Sleep(2000); Console.WriteLine($"****************DoSomethingLong {name} End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} {lResult}***************"); } #endregion
-
异步
/// <summary> /// 异步方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAsync_Click(object sender, EventArgs e) { Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); Action<string> action = this.DoSomethingLong; action.Invoke("btnAsync_Click_1"); // 同步方法 会等待 action("btnAsync_Click_2"); action.BeginInvoke("btnAsync_Click_3",null,null);//发起调用不等待 非阻塞,委托的异步调用 Console.WriteLine($"****************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); }
-
Thread是C#语言对线程对象的封装,是对方法执行的描述
同步:完成计算之后,再进入下一行
异步:不会等待方法的完成,会直接进入下一行 非阻塞 -
C# 异步和多线程有什么差别
多线程就是多个thread并发;
异步是硬件式的异步
异步多线程--thread pool task
修改异步方法:
private void btnAsync_Click(object sender, EventArgs e) { Console.WriteLine($"****************btnAsync_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); Action<string> action = this.DoSomethingLong; for (int i = 0; i < 5; i++) { //Thread.Sleep(5); string name = string.Format($"btnAsync_Click_{i}"); //action.BeginInvoke(name, r => //{ // //action.EndInvoke(r);//主动调用EndInvoke 可以让线程更好的重用 //}, null); action.BeginInvoke(name, null, null); } Console.WriteLine($"****************btnAsync_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); } #endregion
-
同步方法卡界面,主(UI)线程忙于计算;
异步多线程方法不卡界面,主线程完事儿了,计算任务交给子线程在做;
winform提升用户体验;web一个业务操作后要发邮件,异步发送邮件 -
同步方法慢,只有一个线程干活;
异步多线程方法快,因为多个线程并发运算;
并不是线性增长,a资源换时间,可能资源不够 b 多线程也有管理成本
但线程并不是越多越好
多个独立任务可以同时运行; -
异步多线程无序:启动无序 执行时间不确定 结束也无序
一定不要通过等几毫秒的形式来控制启动/执行时间/结束
-
异步回调
#region AsyncAdvanced /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAsyncAdvanced_Click(object sender, EventArgs e) { Console.WriteLine($"****************btnAsyncAdvanced_Click Start {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); Action<string> action = this.DoSomethingLong; IAsyncResult asyncResult = null; AsyncCallback callback = ia => { Console.WriteLine(object.ReferenceEquals(asyncResult,ia)); Console.WriteLine(ia.AsyncState); Console.WriteLine($"到这里计算完成了。{Thread.CurrentThread.ManagedThreadId}"); }; asyncResult =action.BeginInvoke("btnAsyncAdvanced_Click", callback, "hao"); Console.WriteLine($"全部计算真的都完成了,然后给用户返回 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); Console.WriteLine($"****************btnAsyncAdvanced_Click End {Thread.CurrentThread.ManagedThreadId.ToString("00")} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}***************"); } #endregion
-
异步调用之后再进行后续操作,通过异步回调来控制顺序
BeginInvoke先完成委托线程方法,执行完之后,把结果作为callBack的参数传进去执行回调,第三个参数就是一个信息 -
异步的等待
-
文件上传
int i = 0; while (!asyncResult.IsCompleted) // 卡界面,主线程忙于等待 { // 可以等待,边等待边做其他操作 // 可能最多200ms的延迟 if (i < 10) { Console.WriteLine($"文件上传完成{i++ * 10}"); } else { Console.WriteLine($"文件上传完成99.9%..."); } Thread.Sleep(200); } Console.WriteLine($"上传成功了...");
- 通过信号等待
asyncResult.AsyncWaitHandle.WaitOne(); // 等待任务的完成 asyncResult.AsyncWaitHandle.WaitOne(-1); asyncResult.AsyncWaitHandle.WaitOne(1000);// 限时等待:最多等1000ms
- EndInvoke等待
action.EndInvoke(asyncResult); // 可以等待 可以获取返回值
{ Func<int> func = () => { Thread.Sleep(2000); return DateTime.Now.Day; }; Console.WriteLine($"func.Invoke()={func.Invoke()}"); IAsyncResult asyncResult = func.BeginInvoke(r => { // func.EndInvoke(r); //也可以写在里面 Console.WriteLine(r.AsyncState); }, "hello"); Console.WriteLine($"func.EndInvoke(asyncResult)={func.EndInvoke(asyncResult)}"); }
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/18210661
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)