AsParallel如何工作?

9

以下测试程序似乎没有任何作用,这是因为我使用的列表太小了吗?

static void Main(string[] args)
{
    List<int> list = 0.UpTo(4);

    Test(list.AsParallel());
    Test(list);
}

private static void Test(IEnumerable<int> input)
{
    var timer = new Stopwatch();
    timer.Start();
    var size = input.Count();
    if (input.Where(IsOdd).Count() != size / 2)
        throw new Exception("Failed to count the odds");

    timer.Stop();
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
}

private static bool IsOdd(int n)
{
    Thread.Sleep(1000);
    return n%2 == 1;
}

两个版本运行时间均为4秒。


2
你是如何获得 Upto 扩展方法的? - thewpfguy
3个回答

25

任务并行库关注序列的静态类型。序列应该是IParallelEnumerable<T>,这样操作才能由TPL处理。当调用Test时,您将集合强制转换回IEnumerable<T>。因此,编译器会将对序列的.Where调用解析为由TPL提供的并行版本而不是System.Linq.Enumerable.Where扩展方法。


7

(由于这个问题在谷歌搜索中排名很高,因此更新为.NET4)

只需要进行一些更改,您的示例就可以按照您预期的方式工作。

List<int> list = 0.UpTo(4);更改为var list = Enumerable.Range(0, 4);

如果您添加一个带有ParallelQuery签名的函数重载,则您的示例将起作用...

    private static void Test(ParallelQuery<int> input)
    {
        var timer = new Stopwatch();
        timer.Start();

        int size = input.Count();
        if (input.Where(IsOdd).Count() != size / 2)
        {
            throw new Exception("Failed to count the odds");
        }
        timer.Stop();

        Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
    }

或者,您可以使用LINQ语法...
    private static void Test(ParallelQuery<int> list)
    {
        var timer = Stopwatch.StartNew();

        if ((from n in list.AsParallel()
             where IsOdd(n)
             select n).Count() != (list.Count() / 2))
        {
            throw new Exception("Failed to count the odds");
        }

        Console.WriteLine("Tested " + list.Count() + " numbers in " + timer.Elapsed.TotalSeconds + " seconds");
    }

希望这可以帮助到一些人!

2

Parallel通过将您的内容放入线程池中来工作。此外,您有多少个核心?如果您在单核心计算机上工作,那么运行时间仍需要约4秒。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接