当前位置:首页 > 网站源码 > 正文内容

源代码编译为可执行程序的过程(源代码编译的基本步骤)

网站源码8个月前 (03-27)201

前言

多线程无处不在,平常的开发过程中,应该算是最常用的基础技术之一了。以下通过Thread、ThreadPool、再到Task、Parallel、线程锁、线程取消等方面,一步步进行演示多线程的一些基础操作。欢迎大家围观。

如果大佬们有其他关于多线程的拓展,也欢迎在评论区进行留言,大佬们的知识互助,是.NET生态发展的重要一环,欢迎大佬们进行留言,帮助更多的人。

以下博客内容使用的一些环境:

系统环境:WIN 10

.NET 环境:.NET 6

VS 环境:VS 2022

其他:没了

正文

1、先创建一个.NET 6控制台项目,用来当做该博客文章的实验使用。

2、快速创建一个线程。ParameterizedThreadStart是一个委托,传入的参数是一个object类型。

展开全文

代码

ParameterizedThreadStart threadStart = new((obj) => {

Console.WriteLine($ "当前线程 的 ID = {Thread.CurrentThread.ManagedThreadId}");

});

Thread thread = new Thread(threadStart);

thread.Start;

Console.WriteLine($ "线程ID = {thread.ManagedThreadId}");

Console.ReadLine;

3、以上代码执行结果下图所示

4、新建一个类TestThread以及一个测试方法,用来做测试使用。

5、在program里面,把输出改成调用上面的方法再进行测试一下。

6、执行以后的输出结果,如下图所示

7、线程的等待(睡眠)。最简单的方式,是直接 Thread.Sleep(毫秒);

8、Thread的Join方法。代表线程执行完毕以后,才可以继续执行后续的代码。

如下图所示,在thread线程内部执行完成以后,很快就接着执行最后的打印输出方法了。

可以和以上的第7点进行比较输出结果。

9、Thread的Join方法,还可以传入参数,参数是毫秒值。

代表等下当前线程执行多长时间,如果超出设定的毫秒数,就不等了,直接执行后续的代码。

10、新增一个Test2方法,用来测试线程池ThreadPool使用。

11、WaitCallback也是一个委托。传入需要在线程池内执行的方法名称。

以下代码内,“线程池”字符串为执行的方法对应的参数。

代码

using MultiThread;

Console.WriteLine( "Hello, World!");

ThreadPool.QueueUserWorkItem(new WaitCallback(TestThread.Test2), "线程池");

Console.ReadLine;

12、除了直接传入回调方法,也可以直接在线程池开启的方法内,直接写代码块来当做多线程执行的部分。如下图所示,睡眠1000ms以及执行的方法,在线程池内运行。

一般用 .Set; 和 .WaitOne; 结对进行,如下图代码、注释部分以及执行结果。(可以对比输出时间)

14、使用Task快读创建一个线程。

如下图所示。最简单的方法:Task.Run(=>{ 代码块;});

15、也可以用以下方式,手动进行start启动,如图的代码所示。

16、也可以使用Task.Factory创建一个任务工厂来实现。

17、如果需要等待子线程执行完毕,才执行后续操作,可以使用Wait; 来实现。

18、如果只想等待子线程执行指定的时间,可以通过使用 Wait(毫秒数); 来实现。

这样等待,例如500ms以后,不管子线程是不是还在浪,都不会等待,直接继续执行后续代码。

19、 如果要在等待一段时间以后执行某些当做,可以使用Task.Delay(时间毫秒数).ContinuwWith( 要执行的代码块);

如下图所示的代码、注释以及运行输出结果。

20、如果有多个任务在执行期间,在任意一个线程执行完毕以后进行执行某种操作,可以使用 ContinueWhenAny来进行。

如下图所示的代码、注释和运行结果,以及图后附有源码。

代码

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>>Hello, World!");

Task[] tasks = new Task[3];

TaskFactory factory = new;

tasks[0] = factory.StartNew(x => {

Thread.Sleep(1000);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> tasks 0");

},null);

tasks[1] = factory.StartNew(x => {

Thread.Sleep(2000);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> tasks 1");

}, null);

tasks[2] = factory.StartNew(x => {

Thread.Sleep(3000);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> tasks 2");

}, null);

factory.ContinueWhenAny(tasks, x =>

{

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 我不晓得要打印啥子 ~ ~ ");

});

Console.ReadLine;

21、如果要等任务全部执行完毕以后才执行某个代码块,可以使用ContinueWhenAll。

22、使用TaskWaitAny 也可以实现任意任务执行完毕以后,执行后续动作。但是会占用主线程资源。

如图所示代码,大佬们应该可以看出来为什么了。

23、同样的,Task也可以在等待全部任务执行完毕以后进行执行后续动作。如下图演示。

24、Parallel允许线程并行执行。同时最大线程执行数量,类似于ThreadPool可以设置最大并发数量类似。其他不多说,看以下的代码和演示效果。

代码

using MultiThread;

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>>Hello, World!");

ParallelOptions parallelOptions = new;

parallelOptions.MaxDegreeOfParallelism = 3;

Parallel.Invoke(parallelOptions,

=>

{

Thread.Sleep(1000);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> para1");

},

=>

{

Thread.Sleep(2000);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> para2");

},

=>

{

Thread.Sleep(3000);

源代码编译为可执行程序的过程(源代码编译的基本步骤)

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> para3");

});

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 我不晓得要打印啥子 ~ ~ ");

Console.ReadLine;

25、Parallel也可以遍历执行。

代码

using MultiThread;

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>>Hello, World!");

ParallelOptions parallelOptions = new;

parallelOptions.MaxDegreeOfParallelism = 3;

Parallel.For(0, 10,parallelOptions, s =>

{

Thread.Sleep(100);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> para{s}");

});

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 我不晓得要打印啥子 ~ ~ ");

Console.ReadLine;

26、新增一个方法,用来测试多线程锁使用。

27、在不加锁的情况下执行执行以下代码,方法体几乎同时被执行。但是实际上方法体如果只允许被同时一个线程访问的话,那么这样搞肯定是会乱子的,所以需要锁。

28、加了锁以后,查看到执行的结果,时间间隔基本上是1s左右,说明该方法体确实一次只被一个线程调用了。

29、另一种锁(原子锁),可以定义一个变量来进行原子交换。它的使用场景,一般是在轮询进行处理某些业务的时候,并且同时只允许一个线程进来,就可以使用这种锁。

和lock锁区别:lock锁是代码还没执行完,线程会一直等待,等执行完了就会继续进来。

如果线程一直被创建,lock外边会堆积越来越多的线程和资源,最严重的情况会导致系统内存不断飙升直到爆满;

原子锁的作用是,用于验证代码块是不是执行完了,还没执行完,就不鸟他了,线程也不会等待下去,而是直接跳过这部分的代码,继续执行后续的操作。如果后续没事情做了,那该干嘛干嘛了。

30、原子锁执行效果如下,一部分线程判断到代码被锁住,就跳过不管了,所以就不会有输出。

31、测试线程取消。先开启一些线程,以及有关的操作,如下图所示。

32、然后执行。结果比较尴尬,显示都是第100号线程,这是因为Task是多线程,在创建过程中,可能已经让i都执行到头了,所以再次获取到的i都是最后的值,即100.

33、在创建任务之前,引入一个中间变量,用来代替被遍历的i。然后执行结果和其他代码说明,如图所示。

34、看不到异常信息,那改成Task直接走一波,然后通过Task.WaitAll;进行捕捉异常信息。

如代码注释和演示截图所示。

代码

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>>Hello, World!");

try

{

Task[] tasks = new Task[100];

CancellationTokenSource cancellation = new CancellationTokenSource;

for(int i = 0; i < 100; i++)

{

string str = i.ToString;

tasks[i]= Task.Run( =>

{

Thread.Sleep(100);

try

{

if(str == "10")

{

throw new Exception($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 第 -{str}- 号线程开始放弃治疗~~ 线程ID = {Thread.CurrentThread.ManagedThreadId}");

}

}

catch (Exception ex)

{

cancellation.Cancel; // 捕获异常,线程后续所有的线程都取消操作

Console.WriteLine(ex.Message);

}

cancellation.Token.ThrowIfCancellationRequested;

if(cancellation.IsCancellationRequested == false) // 默认为 false,代表正常

{

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 第 -{str}- 号线程执行正常~~ 线程ID = {Thread.CurrentThread.ManagedThreadId}");

}

else

{

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 第 -{str}- 号线程执行异常~~ 线程ID = {Thread.CurrentThread.ManagedThreadId}");

}

}, cancellation.Token);

}

Task.WaitAll(tasks);

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> 我不晓得要打印啥子 ~ ~ ");

}

catch (AggregateException ae)

{

foreach (var ex inae.InnerExceptions)

{

Console.WriteLine($ "{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss,fff ")} >>> {ex.Message}");

}

}

Console.ReadLine;

35、以上就是这篇文章的全部内容。如果对你有帮助,欢迎点赞、转发、或留言。

转自:‍果糖大数据科技

转自:‍果糖大数据科技

版权声明:本文来源于网友收集或网友供稿,仅供学习交流之用,如果有侵权,请转告小编或者留言,本公众号立即删除。

支持小薇

关注公众号: DotNet开发跳槽 ❀

点分享

点收藏

点点赞

点在看

扫描二维码推送至手机访问。

版权声明:本文由我的模板布,如需转载请注明出处。


本文链接:http://sdjcht.com/post/58160.html

分享给朋友:

“源代码编译为可执行程序的过程(源代码编译的基本步骤)” 的相关文章

华为p30指令代码大全(华为p30pro代码大全)

华为p30指令代码大全(华为p30pro代码大全)

本篇文章给大家谈谈华为p30指令代码大全,以及华为p30pro代码大全对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、华为p30触摸屏校准指令 2、求华为手机指令大全...

抖音直播复盘是什么意思(抖音直播如何复盘)

抖音直播复盘是什么意思(抖音直播如何复盘)

今天给各位分享抖音直播复盘是什么意思的知识,其中也会对抖音直播如何复盘进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: 1、抖音直播历史回顾显示40场是啥意思...

微信公众平台营销实践结论与反思(微信公众号实践总结)

微信公众平台营销实践结论与反思(微信公众号实践总结)

本篇文章给大家谈谈微信公众平台营销实践结论与反思,以及微信公众号实践总结对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、微信营销成功案例分享5篇 2、如何运营微信公众平...

拉大锯扯大锯的亲子游戏怎么做(拉大锯游戏规则及玩法)

拉大锯扯大锯的亲子游戏怎么做(拉大锯游戏规则及玩法)

今天给各位分享拉大锯扯大锯的亲子游戏怎么做的知识,其中也会对拉大锯游戏规则及玩法进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: 1、幼儿园中班优秀游戏教案《拉大锯...

抖音直播录制的视频在哪里找(抖音直播录制已看的视频在哪里)

抖音直播录制的视频在哪里找(抖音直播录制已看的视频在哪里)

本篇文章给大家谈谈抖音直播录制的视频在哪里找,以及抖音直播录制已看的视频在哪里对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、抖音的录屏保存在哪里? 2、抖音直播怎么看...

Androidstudio音乐播放器源码(Android开发音乐播放器)

Androidstudio音乐播放器源码(Android开发音乐播放器)

今天给各位分享Androidstudio音乐播放器源码的知识,其中也会对Android开发音乐播放器进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: 1、andro...