4

我试图在任务并行库中了解 Task.WaitAll(..)。

我正在使用以下代码运行测试以尝试模拟两个任务,一个将运行比指定的等待时间长(10 秒)的时间(10 秒),另一个比指定的运行时间短(3 秒)等待的时间量。指定的时间量是 5 秒。我使用的代码如下:

Task<int>[] tasks = new Task<int>[]
{
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(10000);
            return 1;
        }),
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(3000);
            return 2;
        })
};

TimeSpan timeSpan = new TimeSpan(0, 0, 5);
Task.WaitAll(tasks,timeSpan);

int[] results = new int[tasks.Length];
for(int i = 0; i < tasks.Length;i++)
{
    Console.WriteLine(tasks[i].Result);
}

至于timeSpan,我也试过直接传入5000而不是timeSpan变量,但它不起作用。我得到以下输出:

1
2

我希望只得到以下输出,因为另一个线程的执行时间比预期的等待时间长。

1

我误解了这一点,还是做错了这个测试?

4

3 回答 3

11

虽然 Task.Delay 是您通常想要使用的(因此您不会在睡眠期间浪费线程),但您的问题实际上与此无关。

这里发生的情况是,当您打印出结果时,您正在访问每个任务的 Result 属性。这会阻止任务完成,因此您在 WaitAll 中等待 5 秒,然后在打印出 10 秒任务的结果时再等待 5 秒。

根据您声明的意图,您需要在访问 Result 之前检查任务状态,因为您的意图不是阻止它,而只是在它碰巧已经完成时打印出来:

int[] results = new int[tasks.Length];
for (int i = 0; i < tasks.Length; i++)
{
    if (tasks[i].IsCompleted)
    {
        Console.WriteLine(tasks[i].Result);
    }
}

顺便说一句,您可以通过添加一些简单的时间检查(例如,使用秒表,像这样)来证明“结果块”是原始代码中发生的事情

Task<int>[] tasks = new Task<int>[]
{
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(10000);
            return 1;
        }),
    Task.Factory.StartNew<int>(()=>
        {
            Thread.Sleep(3000);
            return 2;
        })
};

TimeSpan timeSpan = new TimeSpan(0, 0, 5);
var stopwatch = Stopwatch.StartNew();
Task.WaitAll(tasks, timeSpan);
Console.WriteLine("WaitAll took {0} seconds", stopwatch.Elapsed.TotalSeconds);

int[] results = new int[tasks.Length];
for (int i = 0; i < tasks.Length; i++)
{
    stopwatch = Stopwatch.StartNew();
    Console.WriteLine(tasks[i].Result);
    Console.WriteLine("Printing result took {0} seconds", stopwatch.Elapsed.TotalSeconds);
}

这会产生以下控制台输出:

WaitAll took 4.9996961 seconds
1
Printing result took 5.0050012 seconds
2
Printing result took 0.0004338 seconds
于 2012-09-07T15:39:19.930 回答
3

不要在任务中使用 Thread.Sleep。Task调度程序不保证每个任务一个线程,并且睡眠可能会影响其他任务(请参阅任务忽略 Thread.Sleep)。请改用Task.Delay()

于 2012-09-07T15:17:43.557 回答
0

尝试将您的时间跨度转换为

TimeSpan span = new TimeSpan(0, 0, 0, 10, 0);
//TimeSpan(Days, hours, minutes, seconds, milliseconds);
于 2012-09-07T15:21:29.573 回答