如果其中一个线程的执行时间超过N分钟,则停止Parallel.ForEach

时间:2015-08-11 15:22:27

标签: c# multithreading parallel.foreach

如果其中一个主题执行时间超过2分钟,我正在寻找停止Parallel.ForEach的解决方案。

我认为下一个解决方案因为x2额外线程而不是很好:

Parallel.ForEach(items, (item, opt) =>
{
    var thread = new Thread(() => { /* a process */ });
    thread.Start();

    bool finished = thread.Join(TimeSpan.FromMinutes(2));
    if (!finished)
    {
        thread.Abort();
        opt.Stop();
    }
});

您是否知道更好的解决方案?

1 个答案:

答案 0 :(得分:1)

首先,我想要注意Parallel不会为您的每个项创建一个线程,它将使用默认的ThreadPool,默认情况下线程数等于处理器的核心数。您的代码中的其他问题是您在工作2分钟后没有停止所有任务,您只能取消您等待两分钟的任务。

我建议您从代码中删除Thread用法,并使用single CancellationToken for thema Timeout for it创建一个Tasks数组,并{ {3}}。此外,您的代码应明确检查令牌是否有待取消。

所以你的代码可能是这样的:

var cts = new CancellationTokenSource();
// two minutes in milliseconds
cts.CancelAfter(2000 * 60);

var tasks = new List<Task>();
foreach (var item in items)
{
    // this is needed because of closures work in C#
    var localItem = item;
    tasks.Add(Task.Run(() => 
        { /* a process with a localItem here */ 
            // this check should be repeated from time to time in your calculations
            if (cts.Token.IsCancellationRequested)
            {
                cts.Token.ThrowIfCancellationRequested();
            }
        }
    // all tasks has only one token
    , cts.Token)

}
// this will cancel all tasks after 2 minutes from start
Task.WaitAll(tasks.ToArray(), TimeSpan.FromMinutes(2));
// this will cancel all tasks if one of them will last more than 2 minutes
Task.WaitAll(tasks.ToArray());

<强>更新

正如您所说,每个项目都是独立的,您可以为每个任务创建CancellationTokenSource,但是,正如@ScottChamberlain所说,在这种情况下,太多任务将同时运行。您可以a timeout for TaskFactory,使用一些start them all(或write your own TaskScheduler),或者只需使用Parallel类正确设置Semafor