Parallel.ForEach
需要一个用户定义的工作程序列表和一个与每个工作程序一起执行的非异步程序 Action
。
Task.WaitAll
并Task.WhenAll
要求List<Task>
,根据定义,它们是异步的。
我发现RiaanDP的响应对于理解差异非常有用,但是需要对进行更正Parallel.ForEach
。没有足够的声誉来回应他的评论,因此是我自己的回应。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTest
{
class Program
{
class Worker
{
public int Id;
public int SleepTimeout;
public void DoWork(DateTime testStart)
{
var workerStart = DateTime.Now;
Console.WriteLine("Worker {0} started on thread {1}, beginning {2} seconds after test start.",
Id, Thread.CurrentThread.ManagedThreadId, (workerStart - testStart).TotalSeconds.ToString("F2"));
Thread.Sleep(SleepTimeout);
var workerEnd = DateTime.Now;
Console.WriteLine("Worker {0} stopped; the worker took {1} seconds, and it finished {2} seconds after the test start.",
Id, (workerEnd - workerStart).TotalSeconds.ToString("F2"), (workerEnd - testStart).TotalSeconds.ToString("F2"));
}
public async Task DoWorkAsync(DateTime testStart)
{
var workerStart = DateTime.Now;
Console.WriteLine("Worker {0} started on thread {1}, beginning {2} seconds after test start.",
Id, Thread.CurrentThread.ManagedThreadId, (workerStart - testStart).TotalSeconds.ToString("F2"));
await Task.Run(() => Thread.Sleep(SleepTimeout));
var workerEnd = DateTime.Now;
Console.WriteLine("Worker {0} stopped; the worker took {1} seconds, and it finished {2} seconds after the test start.",
Id, (workerEnd - workerStart).TotalSeconds.ToString("F2"), (workerEnd - testStart).TotalSeconds.ToString("F2"));
}
}
static void Main(string[] args)
{
var workers = new List<Worker>
{
new Worker { Id = 1, SleepTimeout = 1000 },
new Worker { Id = 2, SleepTimeout = 2000 },
new Worker { Id = 3, SleepTimeout = 3000 },
new Worker { Id = 4, SleepTimeout = 4000 },
new Worker { Id = 5, SleepTimeout = 5000 },
};
var startTime = DateTime.Now;
Console.WriteLine("Starting test: Parallel.ForEach...");
PerformTest_ParallelForEach(workers, startTime);
var endTime = DateTime.Now;
Console.WriteLine("Test finished after {0} seconds.\n",
(endTime - startTime).TotalSeconds.ToString("F2"));
startTime = DateTime.Now;
Console.WriteLine("Starting test: Task.WaitAll...");
PerformTest_TaskWaitAll(workers, startTime);
endTime = DateTime.Now;
Console.WriteLine("Test finished after {0} seconds.\n",
(endTime - startTime).TotalSeconds.ToString("F2"));
startTime = DateTime.Now;
Console.WriteLine("Starting test: Task.WhenAll...");
var task = PerformTest_TaskWhenAll(workers, startTime);
task.Wait();
endTime = DateTime.Now;
Console.WriteLine("Test finished after {0} seconds.\n",
(endTime - startTime).TotalSeconds.ToString("F2"));
Console.ReadKey();
}
static void PerformTest_ParallelForEach(List<Worker> workers, DateTime testStart)
{
Parallel.ForEach(workers, worker => worker.DoWork(testStart));
}
static void PerformTest_TaskWaitAll(List<Worker> workers, DateTime testStart)
{
Task.WaitAll(workers.Select(worker => worker.DoWorkAsync(testStart)).ToArray());
}
static Task PerformTest_TaskWhenAll(List<Worker> workers, DateTime testStart)
{
return Task.WhenAll(workers.Select(worker => worker.DoWorkAsync(testStart)));
}
}
}
结果输出如下。执行时间是可比的。我的计算机每周进行一次防病毒扫描时,我进行了此测试。改变测试的顺序确实改变了它们的执行时间。
Starting test: Parallel.ForEach...
Worker 1 started on thread 9, beginning 0.02 seconds after test start.
Worker 2 started on thread 10, beginning 0.02 seconds after test start.
Worker 3 started on thread 11, beginning 0.02 seconds after test start.
Worker 4 started on thread 13, beginning 0.03 seconds after test start.
Worker 5 started on thread 14, beginning 0.03 seconds after test start.
Worker 1 stopped; the worker took 1.00 seconds, and it finished 1.02 seconds after the test start.
Worker 2 stopped; the worker took 2.00 seconds, and it finished 2.02 seconds after the test start.
Worker 3 stopped; the worker took 3.00 seconds, and it finished 3.03 seconds after the test start.
Worker 4 stopped; the worker took 4.00 seconds, and it finished 4.03 seconds after the test start.
Worker 5 stopped; the worker took 5.00 seconds, and it finished 5.03 seconds after the test start.
Test finished after 5.03 seconds.
Starting test: Task.WaitAll...
Worker 1 started on thread 9, beginning 0.00 seconds after test start.
Worker 2 started on thread 9, beginning 0.00 seconds after test start.
Worker 3 started on thread 9, beginning 0.00 seconds after test start.
Worker 4 started on thread 9, beginning 0.00 seconds after test start.
Worker 5 started on thread 9, beginning 0.01 seconds after test start.
Worker 1 stopped; the worker took 1.00 seconds, and it finished 1.01 seconds after the test start.
Worker 2 stopped; the worker took 2.00 seconds, and it finished 2.01 seconds after the test start.
Worker 3 stopped; the worker took 3.00 seconds, and it finished 3.01 seconds after the test start.
Worker 4 stopped; the worker took 4.00 seconds, and it finished 4.01 seconds after the test start.
Worker 5 stopped; the worker took 5.00 seconds, and it finished 5.01 seconds after the test start.
Test finished after 5.01 seconds.
Starting test: Task.WhenAll...
Worker 1 started on thread 9, beginning 0.00 seconds after test start.
Worker 2 started on thread 9, beginning 0.00 seconds after test start.
Worker 3 started on thread 9, beginning 0.00 seconds after test start.
Worker 4 started on thread 9, beginning 0.00 seconds after test start.
Worker 5 started on thread 9, beginning 0.00 seconds after test start.
Worker 1 stopped; the worker took 1.00 seconds, and it finished 1.00 seconds after the test start.
Worker 2 stopped; the worker took 2.00 seconds, and it finished 2.00 seconds after the test start.
Worker 3 stopped; the worker took 3.00 seconds, and it finished 3.00 seconds after the test start.
Worker 4 stopped; the worker took 4.00 seconds, and it finished 4.00 seconds after the test start.
Worker 5 stopped; the worker took 5.00 seconds, and it finished 5.01 seconds after the test start.
Test finished after 5.01 seconds.