C# 异步多线程入门基础
作者:菜鸟厚非 发布时间:2022-01-19 05:23:05
目录
进程、线程
1. 进程
2. 线程
分时、分片
同步、异步
异步、多线程
异步多线程效率
多线程无序性
扩展
异步多线程版本
下一篇:C# 异步多线程入门到精通之Thread篇
进程、线程
1. 进程
首先了解,什么是线程? 即一个应用程序运行时,占用资源的综合是一个进程。Windows 任务管理器里面可以看到,里面一个个都是在运行的进程。
2. 线程
线程是执行流的最小单位。线程其实是看不到的,其实也可以,例如 Windows 任务管理器:正在运行 272 个进程,272 个进程运行了 3909 个线程,也就是一个进程可以拥有多个线程。
分时、分片
现在有个怪相,CPU 实在太快了,内存显卡其他硬件资源其实都跟不上 CPU 的速度,于是就产生了分片的概念。从微观角度来讲,以前电脑很多都是单核,一时刻只能执行一个线程,按照这个道理,为什么我们的计算机还可以同时运行许多个应用呢。但从宏观来说是并发的,多个应用同时执行,我们既可以扫雷也可以完蜘蛛纸牌还可以听音乐。这就是分片,分片会产生一个上下文,假设当前执行扫雷线程,下一个时刻执行蜘蛛纸牌线程,CPU 会将扫雷线程上下文保存起来,切换成蜘蛛纸牌线程,这样进行来回调度,从宏观来看是并发的。
这个补充一点额外知识,多 CPU 多核,本身就可以完成多个线程的计算,可以独立工作。4核8线程,核就是物理的核,线程是虚拟的核,每个核可以进行分片做并发的。
同步、异步
我们开发人员口中常说的同步、异步,其实是对方法执行的描述。因为编程语言本身是没有线程的,它只能去向操作系统申请线程,去执行代码。
同步方法,代码执行第一行到最后一行依次执行到结束,完成第一行之后进入下第二行直到最后一行,这就是同步,阻塞式的。
异步方法,不会等待当前行执行完成,就会进行下一行执行代码,非阻塞式的。
异步、多线程
多线程,就是多个执行流,同时执行。在 C# 中多线程就是多个并发的 Thread 开启多个线程处理任务,利用的可能是 CPU 的多核,也可能是单核 CPU 分片完成执行的任务。
异步,其实是硬件式的异步,其实这个不太好理解。这里就拿文件写入来说
多线程情况,线程会一直从文件写入开始到结束,都参与工作这件事,也就是 CPU 会处理写文件操作,线程会一直等待 CPU 向磁盘写入文件直到完成。
异步情况,线程会给 CPU 发个指令与文件流交个操作系统,线程就可以忙别的事情去了,也就是利用硬件的特性,发个指令让操作系统完成文件写入,线程去执行其他任务,等 CPU 写完后发个指令回来,通知到线程。
有同学会问这个异步怎么写,其实在程序中是写不了这个的,这是操作系统底层的东西,在 WPF 里面就可以直接调用。 C# 中常说的异步多线程指的是 ThreadPool、Task ,都是基于 Thread 完成的,只是 C# 语言进行了封装的。
异步多线程效率
说起异步很多人都知道,同步方法慢,异步多线程快,这个大家心里面都是这么认为的。但效率究竟提升了多少呢
我们看下面程序,定义一个普通方法 Sum 做些 CPU 密集型运算,然后在 Main 方法,分别同步与异步,执行 Sum 方法。即同样的任务使用单线程(主线程)运行五次,再使用多线程开启 5 个线程,分别执行。
public static void Sum(int f)
{
Console.WriteLine($"第{f}次 start:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
decimal s = 0;
for (int i = 0; i < 1000000000; i++)
{
s = s + i;
}
Console.WriteLine($"第{f}次 end:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
}
static void Main(string[] args)
{
Console.WriteLine($"同步 start:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 5; i++)
{
Sum(i);
}
Console.WriteLine($"同步 end:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine();
Console.WriteLine($"异步 start:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
for (int i = 0; i < 5; i++)
{
Action<int> action = Sum;
action.BeginInvoke(i,null,null);
}
Console.WriteLine($"异步 end:{DateTime.Now.ToLongTimeString()},Thread:{Thread.CurrentThread.ManagedThreadId}");
Console.ReadKey();
}
启动程序,可以看到,同步方法1个线程执行了 2 分 40 秒,异步方法 5 个线程执行了 52 秒,很显然异步方法快与同步方法四倍多。
说到这可能有的同学会发现,同步1个线程,异步5个线程,为什么效率不提升五倍呢,不是线性增长呢?其实,异步效率提升受限于资源限制、上下文切换成本
上面我们说过 CPU 的分时分片,即使单核也可以同时运行多个程序,那既要马儿跑得快,又要马儿不吃草,怎么可能呢,这就是上下文切换的管理成本。
资源限制,异步效率不高也可能资源不够。如下,我们启动资源管理器并启动程序,可以看到同步时 CPU 使用的资源并不高执行但时间长,当多线程时 CPU 达到了 100% 但执行时间短,也就是一种资源换时间策略。
多线程无序性
因为计算机的分时分片,会使得多线程无序。即启动无序、执行无序、结束无序。
启动无序,线程是操作系统的,C# 并没有线程,C# 需要向操作系统申请线程,假设同时或者有序向向操作系统申请线程,但操作系统并不是按顺序给线程,可能后申请的先拿到线程,也可能先申请的后拿到线程。
执行无序,程序拿到了操作系统分片的线程后,我们执行的任务运气好了可能后申请的先执行,运气差了先申请的后执行,都是非常常见的。
结束无序,这个受执行无序、分时分片运气、任务量的影响。开始执行无序已经说过;分时分片运气,当我的 CPU 执行一个任务,并不是任务执行完了才会进行上下文的切换去执行其他任务,而是可以随时暂停切换执行其他任务的;任务量就是,做的任务多少不同,即使同一时刻开始执行,完成的时间必然不一样。
扩展
1 . 同一个线程做相同的事情,耗时时间一样吗?
答案:不一样,应为CPU是分片的,运气好疯狂拿时间片,运气不好十次也拿不到。
异步多线程版本
在 .NET 中随着时间的发展,线程是有许多个版本的 1.0 Thread、2.0 TthreadPool、3.0 Task、4.0 Parallel 等,每个版本都是其特点,后面我们一一进行讲解。
来源:https://blog.csdn.net/weixin_46785144/article/details/120959681
猜你喜欢
- Java 反射机制实例详解一、JAVA是动态语言吗?一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,Ja
- java自定义切面增强写代码时会遇到一些有些重复机械的工作, 这个时候就可以运用切面技术来帮我们节约时间介绍如何使用自定义注解增强方法, 实
- 下面是 Java 线程相关的热门面试题,你可以用它来好好准备面试。1) 什么是线程?线程是操作系统能够进行运算调度的最小单位,它被包含在进程
- 原理分析:迅雷的thunder://地址就是将普通url地址加前缀‘AA'、后缀‘ZZ',再base64编码后得到的字符串实
- 在C# Winform 应用程序中,获取某网页的源文件,可以用以下方法:首先引入名称空间using System.IO;using Syst
- Spring自动装配之方法、构造器位置的自动注入1. 注解定义@Autowired的定义信息如下:@Target({ElementType.
- 网上关于如何切换,其实说的很明确,本文主要通过profile进行快速切换已实现在不同场合下,用不同的打包方式。jar到war修改步骤pom文
- 项目中要使用到在线支付功能 目前常用的在线支付手段主要是 支付宝 和微信。 这里我使用的是支付宝支付,支付宝有个好处就是他有一个沙箱模式 即
- 今天来了一个问题:软键盘无法弹出。分析后是因为系统判断当前有外接硬键盘,就会隐藏软键盘。但实际情况并不是这么简单,该问题只有在特定条件下偶现
- 随着使用Spring进行开发的个人和企业越来越多,Spring从一个单一简介的框架变成了一个大而全的开源软件,最直观的变化就是Spring需
- SpringBoot 项目启动之后执行自定义方法的两种方式在测试配置中心的配置时,想在项目启动成功之后打印配置项,然后需要执行自定义的类一般
- 当我们对一些需要用到的资料进行整理时,会发现文件的内存占用很大,不过是下载或者存储,都不是很方便,这时候我们会想到把文件变成zip格式,即进
- Java7引入了Fork Join的概念,来更好的支持并行运算。顾名思义,Fork Join类似与流程语言的分支,合并的概念。也就是说Jav
- 简介redis 多数据源主要的运用场景是在需要使用多个redis服务器或者使用多个redis库,本文采用的是fastdep依赖集成框架,快速
- Java实现远程控制技术java自带的java.net.和java.awt.robot. 的混合可以用于实现通过网络对另一台计算机的远程控制
- 概述线上项目发布一般有以下几种方案:机发布蓝绿部署滚动部署灰度发布停机发布 这种发布一般在夜里或者进行大版本升级的时候发布,因为需要停机,所
- 一.对象在JVM的内存结构JAVA内存管理由JVM来管理。1)堆,所有new出来的对象(包括成员变量)2)栈,所有局部变量(包括方法的参数)
- 需求:接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承实体类(concrete class)?抽象类中是否
- 前言在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,例如使用devtool来实现
- 在阅读这篇文章之前,大家可以先看下《Java多线程atomic包介绍及使用方法》,了解atomic包的相关内容。一、何谓Atomic?Ato