C#多线程之Parallel类的用法
作者:Ruby_Lu 发布时间:2023-05-15 06:02:03
Parallel类是对线程的一个抽象。该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性。
Paraller类定义了数据并行地For和ForEach的静态方法,以及任务并行的Invoke的静态方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中调用相同的代码,Paraller.Invoke()允许调用不同的方法。
1.Parallel.For
Parallel.For()方法类似C#语法的for循环语句,多次执行一个任务。但该方法并行运行迭代,迭代的顺序没有定义。
Parallel.For()方法中,前两个参数定义了循环的开头和结束,第三个参数是一个Action委托。Parallel.For方法返回类型是ParallelLoopResult结构,它提供了循环是否结束的信息。
Parallel.For有多个重载版本和多个泛型重载版本。
示例:
static void ForTest()
{
ParallelLoopResult plr =
Parallel.For(0,10,i => {
Console.WriteLine("{0},task:{1},thread:{2}",i,Task.CurrentId,Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(5000);
});
if (plr.IsCompleted)
Console.WriteLine("completed!");
}
输出:
任务不一定映射到一个线程上。线程也可以被不同的任务重用。
上面的例子,使用了.NET 4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一个异步(http://www.cnblogs.com/afei-24/p/6757361.html)方法,用于释放线程供其它任务使用。
示例:
static void ForTestDelay()
{
ParallelLoopResult plr =
Parallel.For(0, 10,async i => {
Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
});
if (plr.IsCompleted)
Console.WriteLine("completed!");
Console.ReadKey();
}
输出:
上面代码使用了await关键字进行延迟,输出结果显示延迟前后的代码运行在不同的线程中。而且延迟后的任务不再存在,只留下线程,这里还重用了前面的线程。另一个重要的方面是,Parallel类的For方法并没有等待延迟,而是直接完成。parallel类只等待它创建的任务,而不等待其它后台活动。所以上面代码使用了Console.ReadKey();使主线程一直运行,不然很可能看不到后面的输出。
2.提前停止Parallel.For
For()方法的一个重载版本接受第三个Action<int,ParallelLoopState>委托类型的参数。使用这个方法可以调用ParallelLoopState的Break()或Stop()方法,以停止循环。
注意,前面说到,迭代的顺序是没有定义的。
示例:
static void ForStop()
{
ParallelLoopResult plr =
Parallel.For(0,10,(int i,ParallelLoopState pls)=> {
Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
if (i > 5)
pls.Break();
});
Console.WriteLine("is completed:{0}",plr.IsCompleted);
Console.WriteLine("最低停止索引:{0}",plr.LowestBreakIteration);
}
输出:
迭代值在大于5时中断,但其它已开始的任务同时执行。
3.对Parallel.For中的每个线程初始化
Parallel.For方法使用多个线程来执行循环,如果需要对每个线程进行初始化,就可以使用Parallel.For<TLocal>()方法。除了from和to对应的值之外,Parallel.For方法的泛型版本还接受3个委托参数:
第一个委托参数的类型是Func<TLocal>,这个方法仅对用于执行迭代的每个线程调用每一次。
第二个委托参数为循环体定义了委托。该参数类型是Func<int, ParallelLoopState, TLocal, TLocal>。其中第一个参数是循环迭代,第二个参数ParallelLoopState允许停止循环,第三个参数接受从上面参数委托Func<TLocal>返回的值,该委托还需返回一个TLocal类型的值。该方法对每次迭代调用。
第三个委托参数指定一个委托Action<TLocal>,接受第二个委托参数的返回值。这个方法仅对用于执行迭代的每个线程调用每一次。
示例:
static void ForInit()
{
ParallelLoopResult plr =
Parallel.For(0,10,()=> {
Console.WriteLine("init thread:{0},task:{1}",Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
return Thread.CurrentThread.ManagedThreadId.ToString();
},
(i, pls,strInit)=> {
Console.WriteLine("body:{0},strInit:{1},thraed:{2},task:{3}",i,strInit,Thread.CurrentThread.ManagedThreadId,Task.CurrentId);
return i.ToString();
},
(strI)=> {
Console.WriteLine("finally {0}",strI);
});
}
输出:
4.Parallel.ForEach
Parallel.ForEach方法遍历实现了IEnumerable的集合,类似于foreach,但以异步方式遍历。没有确定遍历顺序。
示例:
static void ForeachTest()
{
string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
ParallelLoopResult plr = Parallel.ForEach<string>(data, s =>
{
Console.WriteLine(s);
});
if (plr.IsCompleted)
Console.WriteLine("completed!");
}
如果需要中断,可以使用ForEach的重载版本和参数ParallelLoopState。
访问索引器:
ParallelLoopResult plr1 = Parallel.ForEach<string>(data, (s,pls,l) =>
{
Console.WriteLine("data:{0},index:{1}",s,l);
});
5.Parallel.Invoke
如果多个任务并行运行,可以使用Parallel.Invoke方法。该方法允许传递一个Action委托数组。
static void ParallerInvoke()
{
Action[] funs = { Fun1,Fun2};
Parallel.Invoke(funs);
}
static void Fun1()
{
Console.WriteLine("f1");
Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
}
static void Fun2()
{
Console.WriteLine("f2");
Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
}
来源:https://www.cnblogs.com/afei-24/p/6904179.html


猜你喜欢
- 前言PowerManagerService之亮屏流程分析 分析了亮屏的流程,并归纳出了一个适用于亮屏或灭屏的通用的流程。 但是,灭屏流程还有
- 什么是容器?在Java的GUI界面设计中,关于容器的理解,从字面意思我们就可以认为它是存放控件的地方,而这个地方依托在窗体之上,常用的容器是
- 使用例子如下,用JAVA 运行Sort1, 输入你要排序的文件路径 , 如 例子是对H:\下的文件和它所有子文件夹下的文件进行排序2, 输入
- 本节,我们从Rxjava使用代码入手,去结合自己已有的知识体系,加查阅部分源码验证的方式,来一起探索一下Rxjava实现的基本原理。为了本文
- 需求:假设我们的APP有3个页面AActivity,BActivity,CActivity,我们的APP需要一直运行在前台(特殊设备),要求
- 介绍本篇给大家带了的是ViewFlipper,它是Android自带的一个多页面管理控件,且可以自动播放! 和ViewPager不同,Vie
- 首先看一下泛型的基本语法访问修饰符 返回类型 泛型方法名 <T>(T 参数)1):无法在泛型方法内部给任何 T 类型创建实例的对
- 排序二叉树概念二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据
- 前言在开发中,或多或少会使用唤醒锁(wake lock),有的是为了保持屏幕长亮,有的是为了保持 CPU 运行。唤醒锁的本质,其实是对屏幕状
- 0.导入命名空间:using Microsoft.Office.Core;using Microsoft.Office.Interop.Ex
- 如果你发现在一个接口使用有如下定义方法: public String[] getParameters();那么你应该认
- 本文实例为大家分享了Android实现外卖购物车功能的具体代码,供大家参考,具体内容如下先看看效果图:知识点分析效果图来看不复杂内容并没多少
- 本文实例为大家分享了Android Studio实现进度条效果的具体代码,供大家参考,具体内容如下实验作业 要求一个进度条,进度随机效果图x
- 这篇文章主要介绍了java property配置文件管理工具框架过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 本文实例为大家分享了java 利用Socket实现SMTP协议发送邮件的具体代码,供大家参考,具体内容如下package mail;impo
- 说明本实例能够监控聚划算的抢购按钮,在聚划算整点聚的时间到达时自动弹开页面(URL自己定义)。可以自定义监控持续分钟数,同时还可以通过多线程
- 游戏服务器里面总是有一大堆的配置文件需要读取, 而且这些配置文件的读取: * 要不然做成弱类型的, 就是一堆字符串或者数字, 不能看出来错误
- 下面将源代码贴出。 public static class ChineseToPinYin { private static readonl
- 本文实例为大家分享了利用Java实现HDFS文件上传下载的具体代码,供大家参考,具体内容如下1、pom.xml配置<!--配置--&g
- DateTime.Now.ToString("dddd",new System.Globalization.Cultur