.NET的并发编程(TPL编程)是什么?

3 数据并行(Data Parallelism)
3.1 数据并行
数据并行是指对源集合或数组中的元素同时(即并行)执行相同操作的情况。在数据并行操作中,源集合被分区,以便多个线程可以同时在不同的段上操作。

数据并行性是指对源集合或数组中的元素同时任务并行库(TPL)通过system.threading.tasks.parallel类支持数据并行。这个类提供了for和for each循环的基于方法的并行实现。

您为parallel.for或parallel.foreach循环编写循环逻辑,就像编写顺序循环一样。您不必创建线程或将工作项排队。在基本循环中,您不必使用锁。底层工作TPL已经帮你处理。

下面代码展示顺序和并行:

复制代码
// Sequential version
foreach (var item in sourceCollection)
{
Process(item);
}

// Parallel equivalent
Parallel.ForEach(sourceCollection, item => Process(item));
复制代码

并行循环运行时,TPL对数据源进行分区,以便循环可以同时在多个部分上运行。在后台,任务调度程序根据系统资源和工作负载对任务进行分区。如果工作负载变得不平衡,调度程序会在多个线程和处理器之间重新分配工作。
下面的代码来展示如何通过Visual Studio调试代码:

复制代码
public static void test()
{
int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0;

        // Use type parameter to make subtotal a long, not an int
        Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
        {
            subtotal += nums[j];
            return subtotal;
        },
            (x) => Interlocked.Add(ref total, x)
        );

        Console.WriteLine("The total is {0:N0}", total);
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

复制代码
选择调试 > 开始调试,或按F5。
应用在调试模式下启动,并会在断点处暂停。
在中断模式下打开线程通过选择窗口调试 > Windows > 线程。 您必须位于一个调试会话以打开或请参阅线程和其他调试窗口。
在这里插入图片描述
3.2 Parallel.For剖析
查看Parallel.For的底层,

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Func localInit, Func<int, ParallelLoopState, TLocal, TLocal> body, Action localFinally);

清楚的看到有个func函数,看起来很熟悉。

[TypeForwardedFrom(“System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089”)]
public delegate TResult Func();

原来是定义的委托,有多个重载,具体查看文档:https://docs.microsoft.com/en-us/dotnet/api/system.func-4?view=netframework-4.7.2

实际上TPL之前,实现并发或多线程,基本都要使用委托。

TIP:关于委托,大家可以查看(https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/delegates)。或者《细说委托》(https://www.cnblogs.com/laoyu/archive/2013/01/13/2859000.html)

回到顶部
4 数据和任务并行中潜在的缺陷
在许多情况下,parallel.for和parallel.foreach可以比普通的顺序循环提供显著的性能改进。然而,并行循环的工作引入了复杂性,这可能会导致在顺序代码中不常见或根本不会遇到的问题。本主题列举了一些实践来帮您避免这些问题,当你在写并行代码的时候。

4.1 不要假设并行总是很快
在某些情况下,并行循环的运行速度可能比其顺序等效循环慢。基本的经验法则是,具有很少迭代和快速用户委托的并行循环不太可能加快速度。但是,由于有很多因素会影响性能,我建议您测量实际结果。

4.2 避免写入共享缓存
在顺序代码中,读写静态变量或者字段是很正常的。然而,每当多个线程同时访问这些变量时,就有很大的竞争条件潜力。即使您可以使用锁来同步对变量的访问,同步成本也会损害性能。因此,我们建议您尽可能避免或至少限制对并行循环中共享状态的访问。最好的方式是使用Parallel.For 和 Parallel.ForEach的重载方法,在并行循环期间,它们使用System.Threading.ThreadLocal泛型类型的变量来存储线程本地状态。通过使用并行循环,您将产生划分源集合和同步工作线程的开销。并行化的好处进一步受到计算机上处理器数量的限制。在一个处理器上运行多个计算绑定线程并不能加快速度。因此,要注意不要过度使用并行。

过度使用并行最常见的场景发生在嵌套循环中。在大多数情况下,最好仅在外层循环使用并行,除非以下几种场景适用:

内层循环很长
您正在对每笔订单执行昂贵的计算。
目标系统有足够的处理器来处理通过并行处理对客户订单的查询而产生的线程数。
在所有情况下,确定最佳查询形状的最佳方法都是测试和度量。

4.3 避免调用非线程安全的方法
从并行循环中写入非线程安全的实例方法可能会导致数据损坏,这在程序中可能会被检测到,也可能不会被检测到。它可能导致异常。在以下示例中,多线程会尝试同时调用FileStream.WriteByte方法,但是这个是不被支持的。

FileStream fs = File.OpenWrite(path);
byte[] bytes = new Byte[10000000];
// …
Parallel.For(0, bytes.Length, (i) => fs.WriteByte(bytes[i]));
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值