简体   繁体   中英

Stopping Parallel.ForEach if one of threads performs more than N minutes

I'm looking for a solution for stopping Parallel.ForEach if one of threads performs more than 2 minutes.

The next solution I think is not very good because of x2 extra threads:

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

Do you know a better solution for the issue?

First of all, I want to note that Parallel class will not create a thread for each of your item, it will use default ThreadPool , which has by default number of threads equal to processor's cores count. Other problem in your code is that you do not stop all the tasks after 2 minutes of working, you only cancel the one which you've waited for two minutes.

I suggest you remove the Thread usage from your code, and create an array of Tasks with single CancellationToken for them with a Timeout for it or with a timeout for TaskFactory , and start them all . Also your code should explicitly check the token for cancellation pending.

So your code could be something like this:

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

Update:

As you said that the each item is independent, you can create CancellationTokenSource for each task, but, as @ScottChamberlain noted, in this case too many tasks will run in the same time. You can write your own TaskScheduler , use some Semafor (or it's slim version ) or simply use the Parallel class with ParallelOptions.MaxDegreeOfParallelism correctly set.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM