C#进阶2-多线程(原始版)

devtools/2025/1/16 1:47:18/

C#进阶2-多线程

文章目录

  • C#进阶2-多线程
  • 多线程初体验
    • 等待
      • AsyncWaitHandle
      • IsCompleted,EndInvoke
  • 其他本线程类
  • Task
    • 操作
  • 并发问题


多线程初体验

它允许程序在同一时间执行多个任务,从而提高程序的性能和响应速度

 public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){}//异步private void button2_Click(object sender, EventArgs e){// 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("你好"));action.BeginInvoke("btn2 method",calMt,null);//异步调用action("Button 2 Clicked");//调用委托方法action.Invoke("Button 2 Clicked");}private void DoSomething(string message){// 处理传入的字符串Console.WriteLine(message);}

在这里插入图片描述

值得注意的是action调用完回调异步后返回值的类型还是AsyncCallback。从这可以发现异步回调的原理,在执行异步方法后,返回回调函数,然后再调用回调函数。

等待

当我们需要异步方法执行完之后,再去执行最后总的内容,这时候就需要等待了

AsyncWaitHandle

  • 可以延迟等待
    // 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("你好"));var acRe =  action.BeginInvoke("异步方法1",calMt,null);//异步调用action("主线程方法1");//调用委托方法action.Invoke("主线程方法2");//acRe.AsyncWaitHandle.WaitOne();//等待异步执行完acRe.AsyncWaitHandle.WaitOne(1000);//等待1s,不管执行完与否,我都不等待了Console.WriteLine("全部任务执行完毕");

IsCompleted,EndInvoke

  • while (!acRe.IsCompleted)//判断异步方法是否执行完毕
  • EndInvoke:方法用于获取异步调用的结果并确保调用完成
            // 使用 Action 委托,一个参数的委托Action<string> action = DoSomething;//定义一个回调方法,当异步的方法调用完,才执行回调AsyncCallback calMt = new AsyncCallback(ia=> Console.WriteLine("异步执行后完毕"));var acRe =  action.BeginInvoke("异步方法1",calMt,null);//异步调用action.EndInvoke(acRe);action("主线程方法1");//调用委托方法action.Invoke("主线程方法2");Console.WriteLine("全部任务执行完毕");

其他本线程类

  • Thread
  • Task
  • Threadpool
  • Parallel

Task

Task是3.0提出来的基于TheadPool来实现的主流处理多线程的方式

操作

简单介绍一下,其他api可自行查询

  • 几种执行方式,参数都是委托方法
Console.WriteLine($"主线程start=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");//1.操作//1.1 runTask.Run(() => {Console.WriteLine($"我是多线程1=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");});//1.2 factoryvar ft = Task.Factory;ft.StartNew(() => {Console.WriteLine($"我是多线程2=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");});//1.3 startTask t1 = new Task(()=>this.DoSomething("我是多线程2"));t1.Start();Console.WriteLine($"主线程end=》{Thread.CurrentThread.ManagedThreadId.ToString("00")}");
  • 等待多线程执行完毕(主线程阻塞等待,卡UI)
List<Task> taskList = new List<Task>();//1.3 startTask t1 = new Task(()=>this.DoSomething("我是多线程2"));t1.Start();....t2,t3.....//等待taskList.Add(t1);taskList.Add(t2);taskList.Add(t3);Task.WaitAll(taskList.ToArray());

  • 不卡界面使用,主线程不阻塞Task.WhenAll(taskList.ToArray()).ContinueWith((t) => this.DoSomething(“我是回调”)) ;

并发问题

对于共享变量,肯定会存在并发问题,这是由于同一时刻可能有多个线程获取了这个变量的值,当一个线程改变变量的值之后,另外一个线程持有的变量值还是原来的值,此时另外一个变量改变后将会覆盖之前线程改变的变量的值。从而造成并发问题

  • 解决办法
    • lock锁
    • 安全队列
	//使用状态唯一的锁private static readonly object LockShare = new object();private void button_bingfa_Click(object sender, EventArgs e){List<int> initList = new List<int>();int shareSemaPhone = 0;List<Task> taskList = new List<Task>();for(int i = 0; i < 1000; i++){//开辟1000线程任务taskList.Add(Task.Run(() =>{lock (LockShare)//锁{int newI = i;initList.Add(newI);shareSemaPhone += 1;}}));}//等待线程执行完毕Task.WaitAll(taskList.ToArray());Console.WriteLine($"shareSemaPhone=>{shareSemaPhone}");Console.WriteLine($"initList count=>{initList.Count}");}

http://www.ppmy.cn/devtools/150343.html

相关文章

【“软件工程”基础概念学习】

基础和相关概念 英文&#xff1a;Software Engineering 软&#xff1a;物体内部的组织疏松&#xff0c;受外力作用后容易改变形状软件&#xff1a; 计算机系统的组成部分&#xff0c;是指挥计算机进行计算、判断、处理信息的程序系统。通常分为系统软件和应用软件。借指某项活…

FPGA的 基本结构(Xilinx 公司Virtex-II 系列FPGA )

以Xilinx 公司Virtex-II 系列FPGA 为例&#xff0c;其基本结构由下图所示。它是主要由两大部分组成&#xff1a;可编程输入/输出&#xff08;Programmable I/Os&#xff09;部分和内部可配置&#xff08;Configurable Logic&#xff09;部分。 可编程输入/输出&#xff08;I/Os…

Vue_API文档

Vue API风格 Vue 的组件可以按两种不同的风格书写&#xff1a;选项式 API&#xff08;Vue2&#xff09; 和组合式 API&#xff08;Vue3&#xff09; 大部分的核心概念在这两种风格之间都是通用的。熟悉了一种风格以后&#xff0c;你也能够很快地理解另一种风格 选项式API(Opt…

LeetCode::2270. 分割数组的方案数

2270. 分割数组的方案数 思路 前缀和 提示 给你一个下标从 0 开始长度为 n 的整数数组 nums 。 如果以下描述为真&#xff0c;那么 nums 在下标 i 处有一个 合法的分割 &#xff1a; 前 i 1 个元素的和 大于等于 剩下的 n - i - 1 个元素的和。下标 i 的右边 至少有一个 元…

Spring FactoryBean到仿照mybatis @Mapper的实现

目录 FactoryBean原理FactoryBean例子org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean mybatis mapper bean的手动实现思考复习下Jdbc传统sql查询做法Mapper接口实现思路复习批量注册beanDefinition: ConfigurationClassPostProcessor自定义实现Mapp…

29、Spark写数据到Hudi时,同步hive表的一些坑

1.hudi的同步hive表没有comment 原以为hudi同步的hive表是根据数据写入的dataframe的schema创建的。就和spark write hive时类似&#xff0c;查看源码后发现不是。 1.1 hudi同步hive的模式 HMS , JDBC , HIVESQL。我这儿常用的是HMS和JDBC 各个同步模式对应的执行器&#x…

深入Android架构(从线程到AIDL)_27 Messager框架与IMessager接口03

目录 3、 双向沟通的Messenger框架 基本設計原則 4、 IMessenger接口 使用AIDL 3、 双向沟通的Messenger框架 这个Messenger框架是对Binder框架加以扩充而来的。 在双向沟通上&#xff0c;也继承了Binder框架机制。Binder框架双向沟通的应用情境是&#xff1a;当myActivit…

求矩阵不靠边元素之和(PTA)C语言

求矩阵的所有不靠边元素之和&#xff0c;矩阵行的值m从键盘读入(2<m<10)&#xff0c;调用自定义函数Input实现矩阵元素从键盘输入&#xff0c;调用Sum函数实现求和。(只考虑float型&#xff0c;且不需考虑求和的结果可能超出float型能表示的范围)。 函数接口定义&#x…