Мне было интересно, если использование TaskCompletitionSource является плохим выбором - PullRequest
0 голосов
/ 31 января 2020

Я должен добавить, что я не являюсь опытным специалистом по Stackoverflow, поэтому я рад обратной связи относительно того, почему мой вопрос может здесь не подходить.

Ожидание TaskCompletitionSource плохая вещь при переносе не асинхронного c вызова?

Вот мой пример использования:

У меня есть класс обработчика, который вызывает функцию Func<T, Task> callback, когда происходит событие. Обработчик вызывается извне моего приложения и уведомляет мой пользовательский интерфейс. Есть два метода A и B, которые используются как обратный вызов. A, где вызывается asyn c HTTP Client, и B, где я делаю вычисления. В обоих случаях вызов await разморозит пользовательский интерфейс, а затем свойства будут обновлены.

A:

public async Task A(){
 result = await CallHttpClient(...) // unfreeze UI
 // ... copy image bytes and update UI (long running not async)
 // release bytes in calling method
}

B:

public async Task B(){
 var  tcs = new TaskCompletionSource<bool>();
 await tcs.Task; // unfreeze UI
 // ... copy image bytes and update UI (long running not async)
 tcs.SetResult(true); // release bytes in calling method
}

Мой вопрос здесь, так ли это плохая практика использовать TaskCompletionSource для переноса не асинхронного c вызова?

Документация гласит следующее.

Если вы хотите создать оболочку задачи для существующей асинхронной операции или события, используйте TaskCompletionSource. https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

Другая возможность - вызвать Task.Run (), но мне кажется, что это еще хуже. Неиспользование Asyn c приведет к зависанию пользовательского интерфейса, который на самом деле не тот, который я хочу, хотя это может быть самым чистым решением.

-------> Обновление

Как состояние другими, Task.Run () прекрасно здесь.

Я должен отметить, что мой B: выглядит по-другому B:

public async Task B(...){
 var  tcs = new TaskCompletionSource<bool>();
 // ... duplicate bytes
 tcs.SetResult(true); // release bytes in calling method
 await tcs.Task; // unfreeze UI
 // ... copy image bytes and update UI (long running not async)
}

Найдите лучший вариант с помощью Task.Run () ниже.

Следует также отметить, что когда метод покидает байты (не показано в примере), они освобождаются.

1 Ответ

1 голос
/ 31 января 2020

Невозможно выполнить задачу, связанную с процессором, в фоновом режиме без какой-либо многопоточности.

Этот код ...

var  tcs = new TaskCompletionSource<bool>();
await tcs.Task; // unfreeze UI
// ... copy image bytes and update UI (long running not async)
tcs.SetResult(true); // release bytes in calling method

... заблокирует на await потому что SetResult не вызывается до тех пор, пока не произойдет что-то вроде тупика.

Полагаю, вы могли бы сделать что-то сумасшедшее, как это

var  tcs = new TaskCompletionSource<bool>();
Parallel.Invoke
(
    () => await tcs.Task,
    () => {
         // ... copy image bytes and update UI (long running not async)
        tcs.SetResult(true); // release bytes in calling method
    }
);

Но я не уверен это тоже подойдет. Стандартный способ сделать это -

await Task.Run( () => {
    // ... copy image bytes and update UI (long running not async)
});

..., который, безусловно, легче следовать, и для этого и предназначен Task.Run().

...