×

Loading...
Ad by
  • 推荐 OXIO 加拿大高速网络,最低月费仅$40. 使用推荐码 RCR37MB 可获得一个月的免费服务
Ad by
  • 推荐 OXIO 加拿大高速网络,最低月费仅$40. 使用推荐码 RCR37MB 可获得一个月的免费服务

强悍的.Net并行处理技术,居然被微软做得如此简单,在多核CPU上利用.net并行技术大幅提升系统性能

本文发表在 rolia.net 枫下论坛昨天受Deepblue的PLINQ启发,到微软网站上下载了一个Parallel Extensions to the .NET Framework 2008/6月的CPT版,简单试用了一下,感觉其功能强大,简单易用,如果你的计算机是2个核以上的,强烈推荐使用这一技术

步骤:
下载 Parallel Extensions to the .NET Framework
http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&displaylang=en

然后安装,当然前提是你已经安装了.net 3.5

然后打开VS2008,在新建的Project中的References中加入System.Threading(这个时候System.Threading已经支持并行了,加入了一个Parallel class)

好了,现在就可以做一个小程序用并行技术试试行能提升有多强了


假设我们要copy 2个目录中的所有.txt文件,每个目录中有5000个txt files,我们先用传统的方式,一个一个的Copy,程序如下:

using System;
using System.Collections.Generic;
using System.IO
using System.Threading;
using System.Linq;

static void Lab()
{
DirectoryInfo[] sourceDirPool = new DirectoryInfo[]
{
new DirectoryInfo(@"c:\............."),
new DirectoryInfo(@"C:\.............")
};

string targetDirPath = @"D:\....................";
DirectoryInfo targetDir = new DirectoryInfo(targetDirPath);

var sw = new Stopwatch();
sw.Start();
Console.WriteLine("一个一个的 Copy 开始..");

foreach (var s in sourceDirPool.SelectMany(x => x.GetFiles("*.txt")))
{
s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
}

sw.Stop();
Console.WriteLine(sw.Elapsed.ToString()); // 打印执行时间
}

我的机器 Core 2 6600, 2.4G, 执行时间 146秒

然后用并行技术重新改写 里面的Copy语句:


foreach (var s in sourceDirPool.SelectMany(x => x.GetFiles("*.txt")))
{
s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
}
替换成

Parallel.ForEach(sourceDirPool.SelectMany(x => x.GetFiles("*.txt")),
s =>
{
s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
});

这次时间变为可怕的81秒,是上一次顺序Copy的55%,性能提升接近一倍


这这里简单解释一下 Paraller.ForEach,这是一个static的函数,有很多不同的签名形式。
其中我在上边程序里面用到的签名是

ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body);

第一个签名IEnumerable<TSource> source非常好理解,就是一个实现了IEnumerable接口的object,在这里是
sourceDirPool.SelectMany(x => x.GetFiles("*.txt")),这个SelectMany返回一个IEnumerable<FileInfo>的object,
里面存着两个目录中所有需要copy的.txt文件信息

第二个签名Action<TSource> body,刚开始看有些费解,其实很简单,Action<>系列是.net系统提供的函数delegate,它同样有很多变种,在这里
Action<TSource> body意思是 你必须实现这么一个函数,这个函数有一个输入参数TSource,但是没有返回值。所有的Action系列delegate都是没有返回值的。与之相对应的是另外一组经常在Linq里面用到的系统delegate,就是FUNC<>系列,它则必须有一个返回值,
比如我们经常用到的(IEnumerable.Where( 里面就是一个 FUNC<TSource,bool> body类型的degelate,意思是你的这个degelate必须返回一个bool的值)

在这里,我用了一个兰姆达表达式来表示这个Action, 就是 s=> {},用.net 2.0的语法可以用new delegate (string s) { ..... }来代替,1.1的语法就要在其他地方写一个函数,然后用函数名来代替。

有时候我在想C#在一步一步的和函数语言接轨,或许有一天F#和C#就看不出来有什么区别了

Paraller.ForEach只是Paraller类的其中一项激动人心的功能,类似的还有Paraller.Invoke,它可以并行执行用户所指定的任意多个函数,我还没有测试,但相信性能提升同样大大的更多精彩文章及讨论,请光临枫下论坛 rolia.net
Report

Replies, comments and Discussions:

  • 工作学习 / 学科技术讨论 / 强悍的.Net并行处理技术,居然被微软做得如此简单,在多核CPU上利用.net并行技术大幅提升系统性能
    本文发表在 rolia.net 枫下论坛昨天受Deepblue的PLINQ启发,到微软网站上下载了一个Parallel Extensions to the .NET Framework 2008/6月的CPT版,简单试用了一下,感觉其功能强大,简单易用,如果你的计算机是2个核以上的,强烈推荐使用这一技术

    步骤:
    下载 Parallel Extensions to the .NET Framework
    http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&displaylang=en

    然后安装,当然前提是你已经安装了.net 3.5

    然后打开VS2008,在新建的Project中的References中加入System.Threading(这个时候System.Threading已经支持并行了,加入了一个Parallel class)

    好了,现在就可以做一个小程序用并行技术试试行能提升有多强了


    假设我们要copy 2个目录中的所有.txt文件,每个目录中有5000个txt files,我们先用传统的方式,一个一个的Copy,程序如下:

    using System;
    using System.Collections.Generic;
    using System.IO
    using System.Threading;
    using System.Linq;

    static void Lab()
    {
    DirectoryInfo[] sourceDirPool = new DirectoryInfo[]
    {
    new DirectoryInfo(@"c:\............."),
    new DirectoryInfo(@"C:\.............")
    };

    string targetDirPath = @"D:\....................";
    DirectoryInfo targetDir = new DirectoryInfo(targetDirPath);

    var sw = new Stopwatch();
    sw.Start();
    Console.WriteLine("一个一个的 Copy 开始..");

    foreach (var s in sourceDirPool.SelectMany(x => x.GetFiles("*.txt")))
    {
    s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
    }

    sw.Stop();
    Console.WriteLine(sw.Elapsed.ToString()); // 打印执行时间
    }

    我的机器 Core 2 6600, 2.4G, 执行时间 146秒

    然后用并行技术重新改写 里面的Copy语句:


    foreach (var s in sourceDirPool.SelectMany(x => x.GetFiles("*.txt")))
    {
    s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
    }
    替换成

    Parallel.ForEach(sourceDirPool.SelectMany(x => x.GetFiles("*.txt")),
    s =>
    {
    s.CopyTo(Path.Combine(targetDir.FullName, s.Name));
    });

    这次时间变为可怕的81秒,是上一次顺序Copy的55%,性能提升接近一倍


    这这里简单解释一下 Paraller.ForEach,这是一个static的函数,有很多不同的签名形式。
    其中我在上边程序里面用到的签名是

    ForEach<TSource>(IEnumerable<TSource> source, Action<TSource> body);

    第一个签名IEnumerable<TSource> source非常好理解,就是一个实现了IEnumerable接口的object,在这里是
    sourceDirPool.SelectMany(x => x.GetFiles("*.txt")),这个SelectMany返回一个IEnumerable<FileInfo>的object,
    里面存着两个目录中所有需要copy的.txt文件信息

    第二个签名Action<TSource> body,刚开始看有些费解,其实很简单,Action<>系列是.net系统提供的函数delegate,它同样有很多变种,在这里
    Action<TSource> body意思是 你必须实现这么一个函数,这个函数有一个输入参数TSource,但是没有返回值。所有的Action系列delegate都是没有返回值的。与之相对应的是另外一组经常在Linq里面用到的系统delegate,就是FUNC<>系列,它则必须有一个返回值,
    比如我们经常用到的(IEnumerable.Where( 里面就是一个 FUNC<TSource,bool> body类型的degelate,意思是你的这个degelate必须返回一个bool的值)

    在这里,我用了一个兰姆达表达式来表示这个Action, 就是 s=> {},用.net 2.0的语法可以用new delegate (string s) { ..... }来代替,1.1的语法就要在其他地方写一个函数,然后用函数名来代替。

    有时候我在想C#在一步一步的和函数语言接轨,或许有一天F#和C#就看不出来有什么区别了

    Paraller.ForEach只是Paraller类的其中一项激动人心的功能,类似的还有Paraller.Invoke,它可以并行执行用户所指定的任意多个函数,我还没有测试,但相信性能提升同样大大的更多精彩文章及讨论,请光临枫下论坛 rolia.net
    • Interesting ! But you have to explicitly use "Parallel.ForEach" in your code. I am wondering what about Java's multi-thread application....without any code change.
    • keep away from dead tech
      • LINQ to SQL is only small part of LINQ. Although I don’t like LINQ to SQL either, I really like other parts of LINQ. BTW, PLINQ is not for LINQ to SQL.
        • LINQ好像不支持其他数据库吧,除了MS SQLServer
          • As I mentioned, major part of LINQ is not database.
            The LINQ is using SQL like query (filter, join, sort, group, union, and so on) to target memory data objects, such as xml, collections, iterating/enumerable objects, and so forth.

            Compare to SQL, using LINQ to query database doesn’t give you much benefit.
    • In addition to use default mode, pipelined processing, you can also use stop-and-go processing or inverted enumeration. That makes processing even more optimum .
    • Good to know. thanks for sharing!