Есть ли способ узнать, ожидает ли задание?
У меня есть метод
public Task<Task> DoSomeWorkOnARemoteMachine()
который очень описательно выполняет некоторую работу на удаленном компьютере с помощью:
- Очередь сообщения на шине сообщений, сигнализирующая о том, что работа должна выполняться
- Удаленный агент берет сообщение и выполняет работу.
- Работа завершается, и агент ставит в очередь сообщение на шине сообщений, чтобы сказать, что работа выполнена
- Приложение, вызвавшее работу, забирает сообщение о том, что работа выполнена
Причина, по которой я использовал Task<Task>
, состоит в том, что первая Task<>
предназначена для очередности сообщения; а внутренний Task
завершается, когда работа завершена на удаленной машине (то есть когда сообщение от агента получено). Любые исключения, которые удаленный агент, захваченный во время выполнения работы, передаются вместе с сообщением о завершении и повторно запускаются, когда внутренний Task
завершается.
Чтобы вызвать этот метод, я использую:
await await DoSomeWorkOnARemoteMachine();
который будет ждать, пока сообщение будет поставлено в очередь для выполнения задания, а также для завершения задания и получения каких-либо исключений. Однако, если меня не интересовало, выполнено ли задание удаленному агенту или нет, я могу назвать его следующим:
await DoSomeWorkOnARemoteMachine();
который не был бы await
внутренним Task
. Однако внутренний Task
(который получает сообщение от удаленного агента и повторно выбрасывает исключения) все равно выполнит в какой-то момент. Я чувствую, что это немного пустая трата, и я бы хотел избежать ее выполнения, когда я не await
для результатов.
Таким образом, мой вопрос: возможно ли Task
"знать", является ли оно await
ed и не выполняется, если это не так, или выполнить какой-либо другой путь кода (например, пустой Task
тела).
Я понимаю, что есть альтернативы, которые я мог бы реализовать, например, передать флаг "огонь и забыть" или добавить перегрузку для "огня и забыть". Было бы здорово, если бы я мог реализовать это без изменения API-интерфейса клиента
Ответы, связанные с другими проектами, которые реализуют такое удаленное выполнение работы, также будут большими!
Ответы
Ответ 1
Я думаю, что вы делаете это довольно запутанно. Не совсем ясно, что означает Task<Task>
. Вместо этого я сделаю так, чтобы ваш метод возвращал что-то вроде Task<Work>
. Тогда тип Work
имел бы такой метод, как GetResultAsync()
, который вернул бы Task
, который представляет выполнение работы на удаленной машине.
Таким образом, у вас есть код, который имеет гораздо более четкое значение, и вы также можете легко узнать, обрабатывать ли ответ, основываясь на том, был ли вызван GetResultAsync()
.
Ответ 2
Это очень интересный вопрос. Однако, если я правильно понял это, я считаю, что это невозможно, так, как вы его представляли, потому что это не имеет смысла (IMO). Давайте посмотрим на следующую модель (пожалуйста, дайте мне знать, если я ошибаюсь):
static async Task<Task> DoSomeWorkOnARemoteMachine()
{
// Point X:
await Task.Delay(1000);
// Point Y:
Console.WriteLine("request sent");
var taskInner = Task.Delay(2000);
// Point A: here you want to know if there an await at Point B
return taskInner;
}
static async Task Test()
{
var taskOuter = DoWorkAsync();
// Point Z:
await taskOuter;
// Point B:
await taskOuter.Result; // await taskInner
Console.WriteLine("request received");
}
В Точке A вам нравится знать, существует ли await
в Точке B. Но в данный момент Point B все еще в будущем, этого еще не произошло. Для этого вам понадобится машина времени:)
[UPDATE] Точно так же в Точке X вы не можете узнать о await
в Точке Z, потому что поток кода еще не достиг Z.
Однако, когда у Y, теоретически вы могли бы узнать о await
в Z (все еще не о B). Хотя, я не знаю, технически ли можно получить такую информацию.
Ответ 3
Я не думаю, что это легко или эффективно достижимо (игра с Task.GetAwaiter - плохая идея, и она не будет доступна изнутри вашей функции, см. ответ Noseratio). Вот альтернативные решения:
Решение n ° 1: параметр функции для Task
выполнения
await DoSomeWorkOnARemoteMachine(false) //Indicates that DoSomeWork shouldn't be executed
Решение № 2: Явное выполнение задачи
Task t = await DoSomeWorkOnARemoteMachine() ;
t.Start(); // For example, if you want to execute the resulting Task.
// You can also dispatch it to an other thread, etc...