目录

  • 前言:
  • 一、使用委托开启多线程
  • 二、使用Thread开启多线程
  • 三、使用ThreadPool开启多线程
  • 四、使用Task开启多线程
  • 五、使用Parallel开启多线程

前言:

线程 被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。

下面的 DoSomethingCallback 方法将贯穿全文。

    private string DoSomething(string name, int millisecondsTimeout){Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId:00}执行");Thread.Sleep(millisecondsTimeout);return name;}private void Callback() { Console.WriteLine("执行回调。"); }

一、使用委托开启多线程

直接使用委托进行异步,.NET Core 已经不支持该方法,使用时将直接抛出错误。

    Func<string, int, string> action = DoSomething;var asyncResult = action.BeginInvoke("JOY", 0, null, null);string result = action.EndInvoke(asyncResult);

二、使用Thread开启多线程

通过扩展 Thread 类创建的线程

    var thread = new Thread(() => DoSomething("JOY",0));thread.Start();

使用 Thread 实现回调

    private void ThreadWithCallBack(ThreadStart threadStart, Action actionCallBack){var method = new ThreadStart(() =>{threadStart.Invoke();actionCallBack.Invoke();});new Thread(method).Start();}// 调用时ThreadWithCallBack(() => DoSomething("JOY", 1000), () => Callback());

实现类型 async/await 的功能,异步,非阻塞,并获取计算结果

    private Func<T> ThreadWithReturn<T>(Func<T> func){T result = default;var method = new ThreadStart(() =>{result = func.Invoke();});var thread = new Thread(method);thread.Start();return new Func<T>(() =>{thread.Join();return result;});}// 调用时var func = ThreadWithReturn(() => DoSomething("JOY", 1000));var result = func.Invoke();

三、使用ThreadPool开启多线程

将方法假如线程池队列以便执行

 ThreadPool.QueueUserWorkItem(o => DoSomething("JOY", 20));

设置线程池数量
设置线程池数量是全局的
委托异步调用 Task Parrallel async/await 全部都是线程池的线程
直接使用 Thread 不受这个数量限制,(但是会占用线程池数量)

    ThreadPool.SetMaxThreads(6, 6);ThreadPool.SetMinThreads(2, 2);ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);Console.WriteLine($"当前电脑最大workerThreads={workerThreads},最大completionPortThreads={completionPortThreads}。");ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);Console.WriteLine($"当前电脑最小workerThreads={workerThreads},最小completionPortThreads={completionPortThreads}。");

使用 ManualResetEvent 等待线程池任务完成

 // 初始设置为 false 指示任务是否终止var mre = new ManualResetEvent(false);ThreadPool.QueueUserWorkItem(o =>{DoSomething("JOY", 20);mre.Set(); // 设置为任务已终止});mre.WaitOne();

四、使用Task开启多线程

使用Task开启子线程执行任务

    var task_1 = new Task(() => DoSomething("JOY", 2000));task_1.Start();var task_2 = Task.Run(() => DoSomething("JOY", 2000));var taskFactory = Task.Factory;Task task_3 = taskFactory.StartNew(() => DoSomething("JOY", 2000));

使用 Delay 方法延迟 Task

 Thread.Sleep(2000);// 与 Sleep(2000) 不同的时,Delay(2000) 不会阻塞当前线程,// 可以理解为在子线程内部加了一个 Sleep(2000).var task = Task.Delay(2000).ContinueWith(t => DoSomething("JOY", 20));

使用 ContinueWith 执行回调

 Task.Run(() => DoSomething("JOY", 2000)).ContinueWith(task => Callback());

获取 Task 的返回值,会阻塞

    var task = Task.Run<string>(() => DoSomething("JOY", 1000));string result = task.Result; // 获取返回值,会阻塞

使用 lock 实现线程安全

 // 在数据需要大量的情况下,可以使用数据分拆,安全又高效var formLock = new object();var numAsync = 0;for (int i = 0; i < 10000; i++){Task.Run(() =>{// 任意时刻只有一个线程能进入方法块lock (formLock) { numAsync++; }});}

使用Task等待所有任务完成,会阻塞

    var taskFactory = Task.Factory;var taskList = new List<Task>();taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_1", 2000)));taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_2", 2000)));taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_3", 2000)));// 阻塞,等待所有任务都完成Task.WaitAll(taskList.ToArray());

等待任务完成后的回调

    var taskFactory = Task.Factory;var taskList = new List<Task>();taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_1", 2000)));taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_2", 2000)));taskList.Add(taskFactory.StartNew(() => DoSomething("JOY_3", 2000)));// 只要有一个任务完成就进行的回调, 这里的 task 就是第一个完成的 TasktaskFactory.ContinueWhenAny(taskList.ToArray(), task => Callback());// 等待所有任务都完成后进的回调,这里的 tasks 就是任务集taskFactory.ContinueWhenAll(taskList.ToArray(), (tasks) => Callback());

控制 Task 的并发数量

 // 不建议用 ThreadPool.SetMaxThreads 和 ThreadPool.SetMinThreads 直接控制ThreadPool.SetMaxThreads(6, 6);ThreadPool.SetMinThreads(2, 2);// 建议使用Task状态控制var tasks = new List<Task>();for (int i = 0; i < 1000; i++){var j = i;if (tasks.Count(task => task.Status != TaskStatus.RanToCompletion) >= 5){Task.WaitAny(tasks.ToArray());tasks = tasks.Where(task => task.Status != TaskStatus.RanToCompletion).ToList();}tasks.Add(Task.Run(() => DoSomething($"JOY_{j + 1}.", 2000)));}

使用 Task.WaitAll 方法 可以捕获多线程异常

    try{var tasks = new List<Task>();for (int i = 0; i < 9; i++){var name = $"JOY_{i}";tasks.Add(Task.Run(() =>{if (name.Equals("JOY_0"))throw new Exception("JOY_0异常");else if (name.Equals("JOY_1"))throw new Exception("JOY_1异常");Console.WriteLine($"name: {name}, 成功。");}));}Task.WaitAll(tasks.ToArray());}catch (AggregateException aex){Console.WriteLine($"异常数量:{aex.InnerExceptions.Count}");}catch (Exception ex){}

使用 CancellationToken 取消其他Task或者自生

    var cts = new CancellationTokenSource();for (int i = 0; i < 20; i++){var name = $"JOY_{i}";Task.Run(() =>{Console.WriteLine($"任务 {name} 开始。");try{if (name.Equals("JOY_6"))throw new Exception("JOY_6异常");if (cts.IsCancellationRequested)DoSomething(name, 2000);elseConsole.WriteLine($"任务 {name} 取消。");}catch (Exception){cts.Cancel();}// 将CancellationToken作为Task.Run的第二个参数,// 使得如果线程还没有启动,被取消就不执行任务}, cts.Token);}

五、使用Parallel开启多线程

Parallel 并发执行多个Action,主线程也会参与计算,会阻塞界面
等于 TaskWaitAll + 主线程计算

    Parallel.Invoke(() => DoSomething("JOY_1", 2000),() => DoSomething("JOY_2", 2000),() => DoSomething("JOY_3", 2000));

Parallel 的 For 循环
同样主线程也会参与计算,会阻塞界面

 Parallel.For(0, 5, i => DoSomething($"JOY_{i}", 2000));

Parallel 的 ForEach 循环
同样主线程也会参与计算,会阻塞界面

 Parallel.ForEach(new int[] { 1, 2, 3, 4, 5 }, i => DoSomething($"JOY_{i}", 2000));

Parallel 控制并发数量

    Parallel.Invoke(options,() => DoSomething("JOY_1", 2000),() => DoSomething("JOY_2", 2000),() => DoSomething("JOY_3", 2000),() => DoSomething("JOY_4", 2000),() => DoSomething("JOY_5", 2000),() => DoSomething("JOY_6", 2000));Parallel.For(0, 9, options, i => DoSomething($"JOY_{i}", 1000));Parallel.ForEach(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },options,i => DoSomething($"JOY_{i}", 2000));

C# 中的多线程实现方式相关推荐

  1. java中的多线程使用方式

    文章目录 1 场景 2 直接创建线程 2.1 Thread创建线程 2.2 Runnable创建线程 2.3 Callable创建线程 3 自定义线程池 3.1 关于线程池 3.1 工具类创建 3.2 ...

  2. 在WPF程序中使用多线程技术

    在WPF应用程序中使用多线程的方式与Windows Forms很类似,区别在于,如果需要更新主线程UI上面的元素,需要用一个特殊的方法(this.Dispatcher.Invoke) 下面是一个简单的 ...

  3. Android中的多线程编程与异步处理

    Android中的多线程编程与异步处理 引言 在移动应用开发中,用户体验是至关重要的.一个流畅.高效的应用能够吸引用户并提升用户满意度.然而,移动应用面临着处理复杂业务逻辑.响应用户输入.处理网络请求 ...

  4. java多线程同步的四种方法_java中实现多线程的两种方法

    java多线程有几种实现方法,都是什么?同步有几种实java中多线程的实现方法有两种:1.直接继承thread类:2.实现runnable接口:同步的实现方法有五种:1.同步方法:2.同步代码块:3. ...

  5. 草根方式学习java中的多线程

    草根方式学习java中的多线程 下面有具体的代码和截图 源码点这里 多线程即在同一时间,可以做多件事情(说白了,就是齐头并进) 单线程就是按部就班 创建多线程有2种方式,分别是继承线程Thread类, ...

  6. java中实现多线程的三种方式

    java中实现多线程的三种方式 1.实现多线程的方法: 在java中实现多线程的两途径:继承Thread类,实现Runable接口(Callable) 2.继承Thread类实现多线程: ​ 继承类T ...

  7. python中实现多线程的几种方式

    python实现多线程的方式大概有 1.threading 2._thread #!/usr/bin/python #!coding:utf-8 import threadingdef action( ...

  8. python3中的多线程

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date    : 2018-07-19 21:50:16 # @Author  : cdl (121 ...

  9. iOS 开发中的多线程

    线程.进程 什么是线程.进程   有的人说进程就像是人的脑袋,线程就是脑袋上的头发~~.其实这么比方不算错,但是更简单的来说,用迅雷下载文件,迅雷这个程序就是一个进程,下载的文件就是一个线程,同时下载 ...

最新文章

  1. DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁
  2. 易评:软银收购ARM会扼住中国芯发展的咽喉吗?
  3. git常用操作命令整理大全(含github操作)
  4. hanoi塔java_Java实现hanoi塔
  5. 程序员简历的10不要与7要
  6. android 微信支付 2,Android微信支付获取二次签名Sign的方法
  7. 一种定力夹具控制系统
  8. python 序列化模块_Python进阶-XII serialize(序列化)、序列化模块
  9. flash builder 4.6 的破解安装
  10. MySQL常用数据字典表设计
  11. Word查找重复的内容
  12. 百度信息流 绑定服务器,【实例】百度信息流账户搭建步骤
  13. 极限中0除以常数_0的美好
  14. CC1310空中升级笔记02 CC26xx_CC13xx_BLE_OAD_例程梳理
  15. Matlab中计算图像的灰度值
  16. 淘宝二手闲鱼平台按关键词搜索闲鱼商品接口,item_search-按关键字搜索闲鱼商品接口接入说明方案
  17. 做一个电商网站需要多少钱
  18. 【19周-星耀】FASTER!FASTER!FASTER!
  19. VScode 淡绿色界面
  20. python中内置数学函数详解和实例应用之三角函数_初级阶段(二)

热门文章

  1. EndNote20中文版分享给大家。
  2. webpack从零开始第1课:安装webpack和webpack-dev-server
  3. Android chrome浏览器的定制
  4. 有关于水果的英文单词
  5. 全球与中国轴向活塞液压马达和泵市场深度研究分析报告
  6. sphinx语音识别(1)-基本介绍
  7. 入坑 Google Glass开发
  8. Bootstrap 3.x 打印问题 打印无法显示背景、字体变黑
  9. word 使用域对公式进行编号
  10. 每周3课:电机、舵机、LM35温度传感器的使用方法 | Mixly纯干货课程