如何才能充分利用 .NET 4.0 中新增强的并行性功能?

发布于 2024-09-02 22:21:34 字数 362 浏览 10 评论 0原文

我对使用 .NET 4.0 中新增强的并行性功能非常感兴趣。

我还看到了在 F# 中使用它的一些可能性,就像在 C# 中一样。

尽管如此,我只能看到 PLINQ 必须提供的内容,例如以下内容:

var query = from c in Customers.AsParallel()
            where (c.Name.Contains("customerNameLike"))
            select c;

这种并行性肯定还有其他用途。

您还有其他使用它的例子吗?这是特别转向 PLINQ,还是有其他像 PLINQ 一样简单的用法?

谢谢! =)

I am pretty much interested into using the newly enhanced Parallelism features in .NET 4.0.

I have also seen some possibilities of using it in F#, as much as in C#.

Despite, I can only see what PLINQ has to offer with, for example, the following:

var query = from c in Customers.AsParallel()
            where (c.Name.Contains("customerNameLike"))
            select c;

There must for sure be some other use of this parallelism thing.

Have you any other examples of using it? Is this particularly turned toward PLINQ, or are there other usage as easy as PLINQ?

Thanks! =)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-09-09 22:21:34

.NET 4 中提供的新并行编程功能不仅限于 PLINQ。

正如 Microsoft 所言:“Visual Studio 2010 和 .NET Framework 4 通过提供新的运行时、新的类库类型和新的诊断工具,增强了对并行编程的支持。这些功能简化了并行开发,使您可以高效地编写代码以自然的方式编写细粒度且可扩展的并行代码,而无需直接使用线程或线程池。”

我建议您查看 .NET Framework 中的并行编程 是一个很好的起点。

总体而言,.NET 4 和 Visual Studio 2010 提供以下功能:

发现任务并行库中的 Task 和 Task{T} 类在创建和协调异步工作时更加灵活。

The new parallel programming features provided in .NET 4 are not limited to just PLINQ.

As stated by Microsoft: "Visual Studio 2010 and the .NET Framework 4 enhance support for parallel programming by providing a new runtime, new class library types, and new diagnostic tools. These features simplify parallel development so that you can write efficient, fine-grained, and scalable parallel code in a natural idiom without having to work directly with threads or the thread pool."

I would recommend that you review Parallel Programming in the .NET Framework as a good starting place.

Overall, .NET 4 and Visual Studio 2010 provide these features:

I personally have found the Task and Task{T} classes in the Task Parallel Library to be more flexible when creating and coordinating asynchronous work.

南汐寒笙箫 2024-09-09 22:21:34

我的团队也刚刚完成了一本关于此的书...

使用 Microsoft® .NE​​T 进行并行编程:
多核架构上的分解和协调设计模式

Colin Campbell、Ralph Johnson、Ade Miller 和 Stephen Toub。前言:Tony Hey

您可以在此处下载草稿和示例:http://parallelpatterns.codeplex.com/

完整的书将于本月晚些时候在 MSDN 上发布,并于 10 月在亚马逊上发布。

对于明目张胆的插件表示歉意,但我认为您可能会发现这些内容确实很有帮助。

更新...

为了回答您选择的问题(如下),聚合的实现(从列表中根据列表内容创建聚合)恰好比 PLinq 更好地映射到 PLinq替代方案,Parallel.ForEach。 PDF 的 p72 上有一个使用 Parallel.ForEach 进行聚合的示例。

如果您只想使用 PLinq 更新集合的内容,则映射要简单得多。例如,以下代码循环访问帐户列表,计算余额趋势并标记预测余额超过透支限额的帐户。

Sequential:

static void UpdatePredictionsSequential(AccountRepository accounts)
{
    foreach (Account account in accounts.AllAccounts)
    {
        Trend trend = SampleUtilities.Fit(account.Balance);
        double prediction = trend.Predict(account.Balance.Length + NumberOfMonths); 
        account.SeqPrediction = prediction;
        account.SeqWarning = prediction < account.Overdraft;
    }
}

PLinq:

static void UpdatePredictionsPlinq(AccountRepository accounts)
{            
    accounts.AllAccounts
        .AsParallel()
        .ForAll(account =>
            {
                Trend trend = SampleUtilities.Fit(account.Balance);
                double prediction = trend.Predict(account.Balance.Length + NumberOfMonths);
                account.PlinqPrediction = prediction;
                account.PlinqWarning = prediction < account.Overdraft;         
            });
}

Parallel.ForEach:

static void UpdatePredictionsParallel(AccountRepository accounts)
{
    Parallel.ForEach(accounts.AllAccounts, account =>
    {
        Trend trend = SampleUtilities.Fit(account.Balance);
        double prediction = trend.Predict(account.Balance.Length + NumberOfMonths);
        account.ParPrediction = prediction;
        account.ParWarning = prediction < account.Overdraft;
    });
}

在某些情况下,PLinq 可能是最具表现力的选择。在其他情况下,Parallel.For/ForEach 可能更好,在某些情况下,这很大程度上取决于程序员的偏好。

但是,任务并行库支持的不仅仅是并行循环和聚合模式。它允许您构建计划在多核硬件上并行执行的任务(任务并行模式):

static int ParallelTaskImageProcessing(Bitmap source1, Bitmap source2,
                                    Bitmap layer1, Bitmap layer2, Graphics blender)
{
    Task toGray = Task.Factory.StartNew(() => SetToGray(source1, layer1));
    Task rotate = Task.Factory.StartNew(() => Rotate(source2, layer2));
    Task.WaitAll(toGray, rotate);
    Blend(layer1, layer2, blender);
    return source1.Width;
} 

它允许您创建任务图,其中一个任务的输出被输入到另一个任务中(任务图或期货模式):

public static int Example4()
{
    var a = 22;

    var cf = Task<int>.Factory.StartNew(() => F2(a));
    var df = cf.ContinueWith((t) => F3(t.Result));
    var b = F1(a);
    var f = F4(b, df.Result);
    return f;
}

其中 F1 -F4 是输入和输出具有依赖性的函数。

它支持创建依赖任务树,以解决排序等分而治之的问题(动态任务并行模式):

static void ParallelWalk<T>(Tree<T> tree, Action<T> action)
{
    if (tree == null) return;
    var t1 = Task.Factory.StartNew(
               () => action(tree.Data));
    var t2 = Task.Factory.StartNew(
               () => ParallelWalk(tree.Left, action));
    var t3 = Task.Factory.StartNew(
               () => ParallelWalk(tree.Right, action));
    Task.WaitAll(t1, t2, t3);
}

它还实现了多个(线程安全)集合以在并行程序中使用。例如,它允许直接实现管道模式:

static void Chapter7Example01Pipeline(int seed)
{
    Console.Write("Begin Pipelined Sentence Builder");

    var buffer1 = new BlockingCollection<string>(BufferSize);
    var buffer2 = new BlockingCollection<string>(BufferSize);
    var buffer3 = new BlockingCollection<string>(BufferSize);

    var f = new TaskFactory(TaskCreationOptions.LongRunning, 
                            TaskContinuationOptions.None);

    var stage1 = f.StartNew(() => ReadStrings(buffer1, seed));
    var stage2 = f.StartNew(() => CorrectCase(buffer1, buffer2));
    var stage3 = f.StartNew(() => CreateSentences(buffer2, buffer3));
    var stage4 = f.StartNew(() => WriteSentences(buffer3));

    Task.WaitAll(stage1, stage2, stage3, stage4);
}

上述所有功能还包含对异常处理和取消的支持,尽管为了清楚起见,我没有在此处显示它们。

My team has also just finished a book on this...

Parallel Programming with Microsoft® .NET:
Design Patterns for Decomposition and Coordination on Multicore Architectures

Colin Campbell, Ralph Johnson, Ade Miller and Stephen Toub. Foreword by Tony Hey

You can download a draft and samples here: http://parallelpatterns.codeplex.com/

The full book will be available on MSDN later this month and on Amazon in October.

Apologies for the blatant plug but I think you might find the content really helpful.

Update...

To answer your question (below) the problem you picked, an implementation of an Aggregation (from a list create an aggregate based on the list content) happens to map far better to PLinq than the alternative, Parallel.ForEach. There's an example of aggregation with Parallel.ForEach on p72 of the PDF.

If you simply want to update the contents of a set using PLinq the mapping is much simpler. For example the following code loops over a list of accounts, calculates a balance trend and flags accounts with predicted balances more than their overdraft limit.

Sequential:

static void UpdatePredictionsSequential(AccountRepository accounts)
{
    foreach (Account account in accounts.AllAccounts)
    {
        Trend trend = SampleUtilities.Fit(account.Balance);
        double prediction = trend.Predict(account.Balance.Length + NumberOfMonths); 
        account.SeqPrediction = prediction;
        account.SeqWarning = prediction < account.Overdraft;
    }
}

PLinq:

static void UpdatePredictionsPlinq(AccountRepository accounts)
{            
    accounts.AllAccounts
        .AsParallel()
        .ForAll(account =>
            {
                Trend trend = SampleUtilities.Fit(account.Balance);
                double prediction = trend.Predict(account.Balance.Length + NumberOfMonths);
                account.PlinqPrediction = prediction;
                account.PlinqWarning = prediction < account.Overdraft;         
            });
}

Parallel.ForEach:

static void UpdatePredictionsParallel(AccountRepository accounts)
{
    Parallel.ForEach(accounts.AllAccounts, account =>
    {
        Trend trend = SampleUtilities.Fit(account.Balance);
        double prediction = trend.Predict(account.Balance.Length + NumberOfMonths);
        account.ParPrediction = prediction;
        account.ParWarning = prediction < account.Overdraft;
    });
}

In some cases, PLinq may be the most expressive choice. In others Parallel.For/ForEach may be better, in some cases it's largly a matter of programmer preference.

However, the Task Parallel Library supports more that the Parallel Loop and Aggregation patterns. It allows you to construct tasks that will be scheduled for parallel execution on multicore hardware (Task Parallelism pattern):

static int ParallelTaskImageProcessing(Bitmap source1, Bitmap source2,
                                    Bitmap layer1, Bitmap layer2, Graphics blender)
{
    Task toGray = Task.Factory.StartNew(() => SetToGray(source1, layer1));
    Task rotate = Task.Factory.StartNew(() => Rotate(source2, layer2));
    Task.WaitAll(toGray, rotate);
    Blend(layer1, layer2, blender);
    return source1.Width;
} 

It allows you to create graphs of tasks where the output of one task is fed into another (Task Graph or Futures pattern):

public static int Example4()
{
    var a = 22;

    var cf = Task<int>.Factory.StartNew(() => F2(a));
    var df = cf.ContinueWith((t) => F3(t.Result));
    var b = F1(a);
    var f = F4(b, df.Result);
    return f;
}

Where F1-F4 are functions who's inputs and outputs have dependencies.

It supports creating trees of dependent tasks, for Divide and Conquer problems like sorting (the Dynamic Task Parallelism pattern):

static void ParallelWalk<T>(Tree<T> tree, Action<T> action)
{
    if (tree == null) return;
    var t1 = Task.Factory.StartNew(
               () => action(tree.Data));
    var t2 = Task.Factory.StartNew(
               () => ParallelWalk(tree.Left, action));
    var t3 = Task.Factory.StartNew(
               () => ParallelWalk(tree.Right, action));
    Task.WaitAll(t1, t2, t3);
}

It also implements several (threadsafe) collections for use in a parallel program. Which allows straightforward implementation of, for example, the Pipeline pattern:

static void Chapter7Example01Pipeline(int seed)
{
    Console.Write("Begin Pipelined Sentence Builder");

    var buffer1 = new BlockingCollection<string>(BufferSize);
    var buffer2 = new BlockingCollection<string>(BufferSize);
    var buffer3 = new BlockingCollection<string>(BufferSize);

    var f = new TaskFactory(TaskCreationOptions.LongRunning, 
                            TaskContinuationOptions.None);

    var stage1 = f.StartNew(() => ReadStrings(buffer1, seed));
    var stage2 = f.StartNew(() => CorrectCase(buffer1, buffer2));
    var stage3 = f.StartNew(() => CreateSentences(buffer2, buffer3));
    var stage4 = f.StartNew(() => WriteSentences(buffer3));

    Task.WaitAll(stage1, stage2, stage3, stage4);
}

All of the above features also contain support for exception handling and cancellation, although for clarity I've not shown them here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文