2

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

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

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

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

这种并行性的东西肯定有其他用途。

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

谢谢!=)

4

3 回答 3

4

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

正如 Microsoft 所说:“ Visual Studio 2010 和 .NET Framework 4 通过提供新的运行时、新的类库类型和新的诊断工具来增强对并行编程的支持。这些特性简化了并行开发,因此您可以编写高效、精细的以一种自然的习惯用法进行粒度化、可扩展的并行代码,而无需直接使用线程或线程池。

我建议您将 .NET Framework 中的并行编程作为一个很好的起点。

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

我个人发现 Task Parallel Library 中的 Task 和 Task{T} 类在创建和协调异步工作时更加灵活。

于 2010-05-28T00:25:32.883 回答
2

我的团队也刚刚完成了一本关于这方面的书......

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

科林·坎贝尔、拉尔夫·约翰逊、阿德·米勒和斯蒂芬·图布。托尼·嘿的前言

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

整本书将于本月晚些时候在 MSDN 上和 10 月在亚马逊上提供。

为公然的插件道歉,但我认为您可能会发现这些内容真的很有帮助。

更新...

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

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

顺序:

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;
    }
}

普林克:

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 可能更好,在某些情况下,这在很大程度上取决于程序员的偏好。

但是,Task Parallel Library 支持的不仅仅是 Parallel Loop 和 Aggregation 模式。它允许您构建将被安排在多核硬件上并行执行的任务(任务并行模式):

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);
}

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

于 2010-08-06T05:53:42.327 回答
1

从 39:30 到 48:36观看这个 Scott Hanselman 的演讲。(从演讲开始 39 分 30 秒开始)。

于 2010-05-28T00:27:06.427 回答