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.rhkb.cn/news/319628.html

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

相关文章

Mybatis进阶2

Mybatis进阶1-CSDN博客 Mybatis入门-CSDN博客 Mybatis入门2-CSDN博客 我们接下来要学习Mybatis的高级查询 我们先在数据库中准备我们需要的数据表 teacher表 课程表&#xff1a;与教师表是一对多的关系&#xff0c;所以有一个外键字段 学生表 由于学生表和课程表是多对多的…

翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习四

合集 ChatGPT 通过图形化的方式来理解 Transformer 架构 翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习一翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习二翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深…

支付宝支付流程

第一步前端&#xff1a;点击去结算&#xff0c;前端将商品的信息传递给后端&#xff0c;后端返回一个商品的订单号给到前端&#xff0c;前端将商品的订单号进行存储。 对应的前端代码&#xff1a;然后再跳转到支付页面 // 第一步 点击去结算 然后生成一个订单号 // 将选中的商…

Python-VBA函数之旅-open函数

目录 一、open函数的常见应用场景 二、open函数使用注意事项 三、如何用好open函数&#xff1f; 1、open函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、open函数的常见应用场…

【JavaEE 初阶(一)】初识线程

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多线程知识 目录 1.前言2.进程3.线程4.线程和进程的区别5.Thread创建线程5.1继承Thread创建线程5.2实现R…

从零开始:Django项目的创建与配置指南

title: 从零开始&#xff1a;Django项目的创建与配置指南 date: 2024/5/2 18:29:33 updated: 2024/5/2 18:29:33 categories: 后端开发 tags: DjangoWebDevPythonORMSecurityDeploymentOptimization Django简介&#xff1a; Django是一个开源的高级Python Web框架&#xff…

AI工具大揭秘:如何改变我们的工作和生活

文章目录 &#x1f4d1;前言一、常用AI工具&#xff1a;便利与高效的结合1.1 语音助手1.2 智能推荐系统1.3 自然语言处理工具 二、创新AI应用&#xff1a;不断突破与发展2.1 医疗诊断AI2.2 智能家居2.3 无人驾驶技术 三、AI工具在人们生活中的应用和影响3.1 生活方式的变化3.2 …

Delta lake with Java--使用stream同步数据

今天继续学习Delta lake Up and Running 的第8章&#xff0c;处理流数据&#xff0c;要实现的效果就是在一个delta表&#xff08;名为&#xff1a;YellowTaxiStreamSource&#xff09;插入一条数据&#xff0c;然后通过流的方式能同步到另外一个delta表 &#xff08;名为&#…

LeetCode题练习与总结:分隔链表--86

一、题目描述 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2]…

神经网络的优化器

神经网络的优化器是用于训练神经网络的一类算法&#xff0c;它们的核心目的是通过改变神经网络的权值参数来最小化或最大化一个损失函数。优化器对损失函数的搜索过程对于神经网络性能至关重要。 作用&#xff1a; 参数更新&#xff1a;优化器通过计算损失函数相对于权重参数的…

ngrinder项目-本地调试遇到的坑

前提-maven mirrors配置 <mirrors><!--阿里公有仓库--><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</ur…

从零开始学AI绘画,万字Stable Diffusion终极教程(二)

【第2期】关键词 欢迎来到SD的终极教程&#xff0c;这是我们的第二节课 这套课程分为六节课&#xff0c;会系统性的介绍sd的全部功能&#xff0c;让你打下坚实牢靠的基础 1.SD入门 2.关键词 3.Lora模型 4.图生图 5.controlnet 6.知识补充 在第一节课里面&#xff0c;我们…

(六)SQL系列练习题(下)#CDA学习打卡

目录 三. 查询信息 16&#xff09;检索"1"课程分数小于60&#xff0c;按分数降序排列的学生信息​ 17&#xff09;*按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩 18&#xff09;*查询各科成绩最高分、最低分和平均分 19&#xff09;*按各科成绩…

总分420+专业140+哈工大哈尔滨工业大学803信号与系统和数字逻辑电路考研电子信息与通信工程,真题,大纲,参考书。

考研复习一路走来&#xff0c;成绩还是令人满意&#xff0c;专业803信号和数电140&#xff0c;总分420&#xff0c;顺利上岸&#xff0c;总结一下自己这一年复习经历&#xff0c;希望大家可以所有参考&#xff0c;这一年复习跌跌拌拌&#xff0c;有时面对压力也会焦虑&#xff…

【iOS】KVC

文章目录 前言一、KVC常用方法二、key与keypath区别key用法keypath用法 三、批量存值操作四、字典与模型相互转化五、KVC底层原理KVC设值底层原理KVC取值底层原理 前言 KVC的全称是Key-Value Coding&#xff0c;翻译成中文叫做键值编码 KVC提供了一种间接访问属性方法或成员变…

从零开始学AI绘画,万字Stable Diffusion终极教程(四)

【第4期】图生图 欢迎来到SD的终极教程&#xff0c;这是我们的第四节课 这套课程分为六节课&#xff0c;会系统性的介绍sd的全部功能&#xff0c;让你打下坚实牢靠的基础 1.SD入门 2.关键词 3.Lora模型 4.图生图 5.controlnet 6.知识补充 在前面的课程中&#xff0c;我…

杭电acm2018 母牛的故事 Java解法 经典递归

标准递归题 先模拟 接着找递归出口 再找递归通式 想想看 今天的母牛等于前一天的母牛数加上今天出生的母牛 而三天前的母牛所有母牛都能生一头 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scnew Scanner(System.in);l…

【计算机网络】计算机网络的定义和分类

一.定义 计算机网络并没有一个精确和统一的定义&#xff0c;在计算机网络发展的不同阶段&#xff0c;人们对计算机网络给出了不同的定义&#xff0c;这些定义反映了当时计算机网络技术的发展水平。 例如计算机网络早期的一个最简单定义&#xff1a;计算机网络是一些互连的、自…

云手机对出海企业有什么帮助?

近些年&#xff0c;越来越多的企业开始向海外拓展&#xff0c;意图发掘更广阔的市场。在这过程中&#xff0c;云手机作为一个新型工具为很多企业提供了助力&#xff0c;尤其在解决海外市场拓展过程中的诸多挑战方面发挥着作用。 首先&#xff0c;云手机的出现解决了企业在海外拓…

线阵相机和面阵相机简介

线阵相机 线阵相机&#xff0c;顾名思义就是所探测的物体要在一个很长的界面上。线阵相机的传感器只有一行感光像素&#xff0c;所以线阵相机一般具有非常高的扫描频率和分辨率。 线阵相机特点 线阵相机使用的线扫描传感器通常只有一行感光单元&#xff08;少数彩色线阵使用…