Тайм-аут для параллельных действий.Итерация ForEach
у меня есть что-то похожее на это в моем коде:
Parallel.ForEach(myList, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item =>
{
Process(item);
});
дело в том, что я делаю кучу вещей внутри Process()
метод (подключение к файловому ресурсу, разбор файла, сохранение в БД и т. д.), И я беспокоюсь, что что-то может пойти не так во время этого процесса, что итерация никогда не закончится...может ли это когда-нибудь случится?
есть ли способ установить тайм-аут для Process()
метод, чтобы избежать в конечном итоге зомби нити?
обновление:
самый простой способ, который я нашел для установки таймаута, - это добавление миллисекунд в CancellationTokenSource
или вызов Wait()
метод на задаче.
Parallel.ForEach(myList, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item =>
{
var cts = new CancellationTokenSource(2000);
Task task = Task.Factory.StartNew(() => Process(item), cts.Token);
});
#2
Parallel.ForEach(myList, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item =>
{
Task task = Task.Factory.StartNew(() => Process(item));
task.Wait(2000);
});
проблема в том, что ни один из этих вариантов могут отменить Process()
метод. Мне нужно проверить что-то в Process()
способ?
3 ответов
попробуйте добавить CancellationToken
в ваш код. Таким образом, в любой момент Вы можете отменить все операции.
затем, вы можете использовать CancelAfter()
метод.
Я закончил тем, что объединил оба варианта. Это работает, но я не знаю, является ли это правильным способом сделать это.
устранение:
Parallel.ForEach(myList, new ParallelOptions { MaxDegreeOfParallelism = 4 }, item =>
{
var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var token = tokenSource.Token;
Task task = Task.Factory.StartNew(() => Process(item, token), token);
task.Wait();
});
и Process()
Я проверяю отмену несколько раз:
private void Process(MyItem item, CancellationToken token)
{
try
{
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
...sentences
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
...more sentences
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
...etc
}
catch(Exception ex)
Console.WriteLine("Operation cancelled");
Я закончил с немного другой реализацией. В моем случае, проверка CancellationToken
внутри Process()
не будет работать из-за потенциально длительных операторов между проверками. Например, если мой тайм-аут составлял 5 секунд, а один оператор занял, скажем, 100 секунд ... Я не знал бы, пока это утверждение не будет завершено, а затем обнаружено if (token.IsCancellationRequested)
.
вот что я закончил делать
Parallel.ForEach(myList, (item) =>
{
Task task = Task.Factory.StartNew(() =>
{
Process(item));
});
if(task.Wait(10000)) // Specify overall timeout for Process() here
Console.WriteLine("Didn't Time out. All's good!");
else
Console.WriteLine("Timed out. Leave this one and continue with the rest");
});
затем в Process()
метод, я добавил дополнительные проверки на потенциально длительные операторы, позволяющие ему изящно обрабатывать тайм-ауты (насколько это возможно). Так что только в худшем случае процесс() должен был быть преждевременно остановлен Task.Wait()
выше.
private void Process(MyItem item)
{
...
cmd.CommandTimeout = 5; // The total of timeouts within Process() were
// set to be less than the total Task.Wait duration.
// Unfortunately some potentially long running methods
// don't have a built in timeout.
...
}