Reputation: 2745
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?
Upvotes: 3
Views: 1427
Reputation: 28355
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.
Upvotes: 2