Основываясь на этом отрывке из вашего комментария ...:
Что я хочу сделать в случае запроса на отмену, так это игнорировать текущий работающий элемент. Меня это больше не волнует, так почему я должен ждать этого?
... и предполагая, что вы действительно в порядке, оставив задание выполненным, выможно просто обернуть задание, которое вы хотите вызвать , в другое Task
, которое будет постоянно запрашивать отмену или завершение, и вместо этого , что Task
. Взгляните на следующий код «проверки концепции», который оборачивает «долго выполняющуюся» задачу в другую задачу, «выполняющую задачи», с постоянным опросом завернутой задачи на предмет завершения, и CancellationToken для отмены (полностью «побуждающий»). «текущий момент», вы, конечно, захотите немного изменить его):
public class LongRunningTaskSource
{
public Task LongRunning(int milliseconds)
{
return Task.Run(() =>
{
Console.WriteLine("Starting long running task");
Thread.Sleep(3000);
Console.WriteLine("Finished long running task");
});
}
public Task LongRunningTaskWrapper(int milliseconds, CancellationToken token)
{
Task task = LongRunning(milliseconds);
Task wrapperTask = Task.Run(() =>
{
while (true)
{
//Check for completion (you could, of course, do different things
//depending on whether it is faulted or completed).
if (!(task.Status == TaskStatus.Running))
break;
//Check for cancellation.
if (token.IsCancellationRequested)
{
Console.WriteLine("Aborting Task.");
token.ThrowIfCancellationRequested();
}
}
}, token);
return wrapperTask;
}
}
Используя следующий код:
static void Main()
{
LongRunningTaskSource longRunning = new LongRunningTaskSource();
CancellationTokenSource cts = new CancellationTokenSource(1500);
Task task = longRunning.LongRunningTaskWrapper(3000, cts.Token);
//Sleep long enough to let things roll on their own.
Thread.Sleep(5000);
Console.WriteLine("Ended Main");
}
... производит следующий вывод:
Starting long running task
Aborting Task.
Exception thrown: 'System.OperationCanceledException' in mscorlib.dll
Finished long running task
Ended Main
Завершенное задание, очевидно, завершается в свое время. Если у вас нет проблем с этим , который часто не случай, надеюсь, это должно соответствовать вашим потребностям.
В качестве дополнительного примера, запускследующий код (позволяющий завершить завершенную задачу до истечения времени ожидания):
static void Main()
{
LongRunningTaskSource longRunning = new LongRunningTaskSource();
CancellationTokenSource cts = new CancellationTokenSource(3000);
Task task = longRunning.LongRunningTaskWrapper(1500, cts.Token);
//Sleep long enough to let things roll on their own.
Thread.Sleep(5000);
Console.WriteLine("Ended Main");
}
... производит следующий вывод:
Starting long running task
Finished long running task
Ended Main
Таким образом, задача запускалась и заканчивалась до истечения времени ожидания иничто не должно было быть отменено. Конечно, ничто не блокируется во время ожидания. Как вы, наверное, уже знаете, конечно, если вы знаете , что используется за кулисами в долговременном коде, было бы хорошо очистить при необходимости.
Надеюсь,Вы можете адаптировать этот пример, чтобы передать что-то подобное в свой ActionBlock.
Отказ от ответственности и примечания
Я не знаком с библиотекой потока данных TPL, так что это, конечно, обходной путь. Кроме того, если все, что у вас есть, например, синхронный вызов метода, на который вы вообще не имеете никакого влияния, тогда вам, очевидно, понадобятся две задачи. Одна задача-обертка, чтобы обернуть синхронный вызов, и другая, чтобы обернуть задачу-обертку, чтобы включить непрерывный опрос статуса и проверки отмены.