C#技巧之同步与异步

区别

首先,同步就是程序从上往下顺序执行,要执行完当前流程,才能往下个流程去。

而异步,则是启动当前流程以后,不需要等待流程完成,立刻就去执行下一个流程。


同步示例

创建一个窗体,往窗体里面添加一个button,写入以下代码。

private void button1_Click(object sender, EventArgs e)
{for (int i = 0; i < 5; i++){method($"button1_click{i}");}}private void method(string str){Console.WriteLine($"{str}在线程{Thread.CurrentThread.ManagedThreadId.ToString()}启动,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");for (var i = 0; i < 1000; i++){Thread.Sleep(1);}Console.WriteLine($"{str}线程{Thread.CurrentThread.ManagedThreadId.ToString()}结束,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");Console.WriteLine("--------------------------------------");}

如果所示,当点击按钮以后,会五次执行method方法,而method方法就是一个从0-999再数数,然后打印启动时间和结束时间。我们看看执行结果。

button1_click0在线程1启动,时间16:239
button1_click0线程1结束,时间18:229
--------------------------------------
button1_click1在线程1启动,时间18:229
button1_click1线程1结束,时间20:209
--------------------------------------
button1_click2在线程1启动,时间20:209
button1_click2线程1结束,时间22:195
--------------------------------------
button1_click3在线程1启动,时间22:195
button1_click3线程1结束,时间24:182
--------------------------------------
button1_click4在线程1启动,时间24:182
button1_click4线程1结束,时间26:169
--------------------------------------

可以看到,button_click是一一对应的,也即是说当click0启动后,要等0完成,才能启动click1,并且,这五个循环,都是在主线程1中执行,这就会导致一个问题,因为控件的创建也是在主线程1中,如果线程1被拿来执行一些长耗时的工作,那么窗体上的控件就会卡住。下面我们再看看异步示例。再创建个button2,添加以下代码。


异步示例

private void button2_Click(object sender, EventArgs e)
{Action<string> action = method;for (int i = 0;i<5;i++){action.BeginInvoke($"button2_click{i}", null, null);}}private void method(string str)
{Console.WriteLine($"{str}在线程{Thread.CurrentThread.ManagedThreadId.ToString()}启动,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");for (var i = 0; i < 1000; i++){Thread.Sleep(1);}Console.WriteLine($"{str}线程{Thread.CurrentThread.ManagedThreadId.ToString()}结束,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");Console.WriteLine("--------------------------------------");
}

同样是执行5次method2,但button2使用的方法是通过委托的异步执行来实现。我们再来看看结果。

button2_click1在线程6启动,时间15:389
button2_click4在线程9启动,时间15:389
button2_click0在线程3启动,时间15:390
button2_click2在线程7启动,时间15:389
button2_click3在线程8启动,时间15:389
button2_click3线程8结束,时间17:369
--------------------------------------
button2_click1线程6结束,时间17:372
--------------------------------------
button2_click4线程9结束,时间17:374
--------------------------------------
button2_click0线程3结束,时间17:374
--------------------------------------
button2_click2线程7结束,时间17:374
--------------------------------------

可以看到,异步执行的话是同时触发五个计数流程,然后通过五个不同的线程来分别进行,所以不仅主线程创建的控件不会卡死,另外,执行时间也比同步要快不少。

但异步会出现一个问题,就是无序,如果有些流程,要先执行完1,再执行2,那么使用上面的方法,就有点难以控制。这时,我们可以使用回调函数,所谓回调函数,就是当异步执行结束以后会执行的函数,这时,只要把下个流程要执行的条件,写在当前流程的回调函数中,那么就可以实现顺序控制了。

private void button2_Click(object sender, EventArgs e)
{Action<string> action = method;AsyncCallback asyncCallback = method2;for (int i = 0;i<5;i++){action.BeginInvoke($"button2_click{i}", asyncCallback, null);}}private void method(string str){Console.WriteLine($"{str}在线程{Thread.CurrentThread.ManagedThreadId.ToString()}启动,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");for (var i = 0; i < 1000; i++){Thread.Sleep(1);}Console.WriteLine($"{str}线程{Thread.CurrentThread.ManagedThreadId.ToString()}结束,时间{DateTime.Now.Second.ToString()}:{DateTime.Now.Millisecond.ToString()}");Console.WriteLine("--------------------------------------");}private void method2(IAsyncResult ia)
{Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}执行完成?"+ia.IsCompleted);}

运行结果:

button2_click0在线程3启动,时间48:919
button2_click1在线程8启动,时间48:919
button2_click2在线程9启动,时间48:919
button2_click3在线程10启动,时间48:921
button2_click4在线程4启动,时间48:922
button2_click0线程3结束,时间50:894
--------------------------------------
线程3执行完成?True
button2_click2线程9结束,时间50:897
--------------------------------------
button2_click1线程8结束,时间50:897
--------------------------------------
线程8执行完成?True
线程9执行完成?True
button2_click3线程10结束,时间50:897
--------------------------------------
线程10执行完成?True
button2_click4线程4结束,时间50:897
--------------------------------------
线程4执行完成?True

可以看到,每个线程执行完以后,都会有反馈,我们可以在反馈函数中写逻辑,这里就不详细叙述了。


控件不在创建线程中被调用

如果控件不在创建线程中被调用,会报错。

创建一个button对象button3和一个label对象lbl,添加以下代码。

 private void button3_Click(object sender, EventArgs e){Thread t1 = new Thread(Method3);t1.Start();}private void Method3(){for (var i = 0; i < 10; i++){Thread.Sleep(1000);ChangeLabel(label1, i.ToString());}}private void ChangeLabel(Label lbl,string str)
{lbl.Text = str;
}

如上,点击button3以后,会启动一个分线程,然后在分线程中执行Method3方法,而Method3方法的操作是,每隔一秒,就改变lbl的text属性。当我们按下button3后,会显示如下结果。

要解决这种方法,就可以使用异步调用。代码如下。

private delegate void MyDel(Label lbl,string str);private void button3_Click(object sender, EventArgs e)
{Thread t1 = new Thread(Method3);t1.Start();
}private void Method3(){for (var i = 0; i < 10; i++){Thread.Sleep(1000);ChangeLabel(label1, i.ToString());}}private void ChangeLabel(Label lbl,string str)
{if (lbl.InvokeRequired)    //如果lbl控件被创建其线程以外的线程调用,那么InvokeRequire为true{MyDel myDel = ChangeLabel;lbl.BeginInvoke(myDel, new object[] { label1, str });    //启动异步调用}else{lbl.Text = str;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/6739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2131 - 枚举-练习-涂国旗

2131 - 枚举-练习-涂国旗 c刷题 超能力编程 分析 枚举涂w的底边和涂b的底边即可 剩下的部分都涂r 数据范围这么小,暴力枚举&#xff0c;代码简单难度低。搜索什么的用不着啦&#xff01; 那么问题来了&#xff1a;怎么枚举呢&#xff1f; 我们只要枚举白与蓝、蓝与红的边界&…

【DPU系列之】DPU中的ECPF概念是什么?全称是什么?(E CPF对标H CPF;embedded CPU function ownership)

ECPF&#xff1a;embedded CPU function ownership。 嵌入式CPU运转ownership。也叫DPU模式&#xff0c;是DPU工作运转3种模式之一&#xff0c;也是默认的模式。这里的嵌入式CPU指的是DPU上ARM CPU&#xff0c;表示网卡所有资源和功能被embedded CPU全权管理&#xff0c;行使所…

【动态规划】投资问题

本文利用markdown基于https://blog.csdn.net/qq_41926985/article/details/105627049重写,代码部分为本人编辑 代码要求 应用动态规划方法&#xff0c;求解投资问题&#xff0c;实现下面的例子。 #define MAX_N 4 //最大投资项目数目 #define MAX_M 5 //最大投资钱数(万元) /…

【机器视觉】yolo-world-opencvsharp-.net4.8 C# 窗体应用程序

这段代码是基于 OpenCvSharp, OpenVinoSharp 和 .NET Framework 4.8 的 Windows Forms 应用程序。其主要目的是加载和编译机器学习模型&#xff0c;对输入数据进行推理&#xff0c;并显示结果。 下面是该程序的主要功能和方法的详细总结&#xff1a; 初始化 OpenVINO 运行时核心…

基于Pytorch深度学习——卷积神经网络(卷积层/池化层/多输入多输出通道/填充和步幅/)

本文章来源于对李沐动手深度学习代码以及原理的理解&#xff0c;并且由于李沐老师的代码能力很强&#xff0c;以及视频中讲解代码的部分较少&#xff0c;所以这里将代码进行尽量逐行详细解释 并且由于pytorch的语法有些小伙伴可能并不熟悉&#xff0c;所以我们会采用逐行解释小…

【DPU系列之】如何通过带外口登录到DPU上的ARM服务器?(Bluefield2举例)

文章目录 1. 背景说明2. 详细操作步骤2.1 目标拓扑结构2.2 连接DPU带外口网线&#xff0c;并获取IP地址2.3 ssh登录到DPU 3. 进一步看看系统的一些信息3.1 CPU信息&#xff1a;8核A723.2 内存信息 16GB3.3 查看ibdev设备 3.4 使用小工具pcie2netdev查看信息3.5 查看PCIe设备信息…

python笔记:gensim进行LDA

理论部分&#xff1a;NLP 笔记&#xff1a;Latent Dirichlet Allocation &#xff08;介绍篇&#xff09;-CSDN博客 参考内容&#xff1a;DengYangyong/LDA_gensim: 用gensim训练LDA模型&#xff0c;进行新闻文本主题分析 (github.com) 1 导入库 import jieba,os,re from ge…

【云原生】Docker 的网络通信

Docker 的网络通信 1.Docker 容器网络通信的基本原理1.1 查看 Docker 容器网络1.2 宿主机与 Docker 容器建立网络通信的过程 2.使用命令查看 Docker 的网络配置信息3.Docker 的 4 种网络通信模式3.1 bridge 模式3.2 host 模式3.3 container 模式3.4 none 模式 4.容器间的通信4.…

Stream流操作

看到Stream流这个概念&#xff0c;我们很容易将其于IO流联系在一起&#xff0c;事实上&#xff0c;两者并没有什么关系&#xff0c;IO流是用于处理数据传输的&#xff0c;而Stream流则是用于操作集合的。 当然&#xff0c;为了方便我们区分&#xff0c;我们依旧在这里复习一下…

长期找 AI 专家,邀请参加线上聊天直播

诚邀 AI 专家参加线上聊天&#xff0c;成为嘉宾。 分享前沿观点、探讨科技和生活 除节假日外&#xff0c;每周举办在线聊天直播 根据话题和自愿形式结合&#xff0c;每期 2~3 位嘉宾 成为嘉宾&#xff0c;见下&#xff1a;

ADS软件(PathWave 先进设计系统软件)分享与安装

ADS软件的简介 ADS软件&#xff08;Advanced Design System&#xff09;主要用于射频&#xff08;RF&#xff09;、微波&#xff08;Microwave&#xff09;和毫米波&#xff08;Millimeter-wave&#xff09;电路的设计、仿真和分析。它提供了一套强大的工具和功能&#xff0c;…

Angular进阶-NVM管理Node.js实现不同版本Angular环境切换

一、NVM介绍 1. NVM简介 Node Version Manager&#xff08;NVM&#xff09;是一个用于管理多个Node.js版本的工具。它允许用户在同一台机器上安装和使用多个Node.js版本&#xff0c;非常适合需要同时进行多个项目的开发者。NVM是开源的&#xff0c;支持MacOS、Windows和Linux…

【解决】docker一键部署报错

项目场景见&#xff1a;【记录】Springboot项目集成docker实现一键部署-CSDN博客 问题&#xff1a; 1.docker images 有tag为none的镜像存在。 2.有同事反馈&#xff0c;第一次启动docker-compose up -d 项目无法正常启动。后续正常。 原因&#xff1a; 1.服务中指定了镜像m…

Jackson-jr 对比 Jackson

关于Jackson-jr 对比 Jackson 的内容&#xff0c;有人在做了一张下面的图。 简单点来说就 Jackson-jr 是Jackson 的轻量级应用&#xff0c;因为我们在很多时候都用不到 Jackson 的很多复杂功能。 对很多应用来说&#xff0c;我们可能只需要使用简单的 JSON 读写即可。 如我们…

【Linux网络】网络文件共享

目录 一、存储类型 二、FTP文件传输协议 2.1 FTP工作原理 2.2 FTP用户类型 2.3 FTP软件使用 2.3.1 服务端软件vsftpd 2.3.2 客户端软件ftp 2.4 FTP的应用 2.4.1 修改端口号 2.4.2 匿名用户的权限 2.4.3 传输速率 三、NFS 3.1 工作原理 3.2 NFS软件介绍 3.3 NFS配…

企业级数据治理学习总结

1. 水在前面 “数据治理”绝对是吹过的牛里面最高大上的题目了&#xff0c;本来想直接以《企业级数据治理》为题来水的&#xff0c;码字前又跑去图书馆借了几本书&#xff0c;翻了几页才发现自己连半桶水都提不起&#xff0c;撑死只能在小屁孩跟前吹吹牛。 好吧&#xff0c;实在…

怎么把jpg图片变成gif?参考这个方法一键制作

Jpg图片如何变成gif图片&#xff1f;Jpg、gif都是最常用的图片格式&#xff0c;想要将这两种格式的图片互相转化的时候要怎么操作呢&#xff1f;想要将jpg图片变成gif方法很简单&#xff0c;只需要使用gif图片制作&#xff08;https://www.gif5.net/&#xff09;工具-GIF5工具网…

华为手机ip地址怎么切换

随着移动互联网的普及&#xff0c;IP地址成为了我们手机上网的重要标识。然而&#xff0c;在某些情况下&#xff0c;我们可能需要切换手机的IP地址&#xff0c;以更好地保护个人隐私、访问特定地区的内容或服务&#xff0c;或者出于其他网络需求。华为手机作为市场上的热门品牌…

用队列实现栈——leetcode刷题

题目的要求是用两个队列实现栈&#xff0c;首先我们要考虑队列的特点&#xff1a;先入先出&#xff0c;栈的特点&#xff1a;后入先出&#xff0c;所以我们的目标就是如何让先入栈的成员后出栈&#xff0c;后入栈的成员先出栈。 因为有两个队列&#xff0c;于是我们可以这样想&…

vue3(实现上下无限来往滚动)

一、问题描述 一般在大屏项目中&#xff0c;很常见的效果&#xff0c;就是容器中的内容缓慢地向下移动&#xff0c;直到底部停止&#xff0c;然后快速滚动回顶部&#xff0c;然后接着缓慢滚动到底部。并且在特定的情况下&#xff0c;还需要进行一些小交互&#xff0c;那就还得让…