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

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

网站源码7个月前 (03-27)198

前言

多线程无处不在,平常的开发过程中,应该算是最常用的基础技术之一了。以下通过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://60200875.com/post/58160.html

分享给朋友:

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

传奇小极品1.76(传奇小极品传奇手游)

传奇小极品1.76(传奇小极品传奇手游)

今天给各位分享传奇小极品1.76的知识,其中也会对传奇小极品传奇手游进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: 1、170复古传奇金币版 1.76小极品什么职...

梦幻西游手游你添加的好友没有加你(梦幻西游手游好友助战怎么没有好友)

梦幻西游手游你添加的好友没有加你(梦幻西游手游好友助战怎么没有好友)

本篇文章给大家谈谈梦幻西游手游你添加的好友没有加你,以及梦幻西游手游好友助战怎么没有好友对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、梦幻西游手游加好友 2、梦幻西游...

安卓html文件怎么打开(安卓html文件查看器)

安卓html文件怎么打开(安卓html文件查看器)

本篇文章给大家谈谈安卓html文件怎么打开,以及安卓html文件查看器对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、手机浏览器能打开html文件吗 2、html文件在...

Vue响应式原理(vue响应式原理简书)

Vue响应式原理(vue响应式原理简书)

今天给各位分享Vue响应式原理的知识,其中也会对vue响应式原理简书进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录一览: 1、Vue3.0采用新特性Proxy来实现数据...

大学生数据新闻可视化作品(大学生数据可视化项目)

大学生数据新闻可视化作品(大学生数据可视化项目)

本篇文章给大家谈谈大学生数据新闻可视化作品,以及大学生数据可视化项目对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、数据可视化的16个经典案例 2、《数据新闻实战》ep...

游戏福利号有骗局吗(游戏福利号是真的吗)

游戏福利号有骗局吗(游戏福利号是真的吗)

本篇文章给大家谈谈游戏福利号有骗局吗,以及游戏福利号是真的吗对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 本文目录一览: 1、网上让自己下载的传奇说是给福利号可信吗 2、大话西游手游福利...