await AsyncMethod() и await await Task.Factory.StartNew‹TResult›(AsyncMethod)

Учитывая следующий метод:

public async Task<MyObject> DoSomethingAsync() {
    // do some work
    await OpenSomeFileAsync();
    return new MyObject();
}

Есть ли разница между:

public async void SomeEventHandler(EventArgs args) {
    var myObject = await await Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
    // do something with myObject
}

и:

public async void SomeEventHandler(EventArgs args) {
    var myObject = await DoSomethingAsync();
    // do something with myObject
}

Я думал, что часть DoSomethingAsync «выполнить некоторую работу» произойдет немедленно в новой задаче в первом случае, но, честно говоря, я не совсем понимаю, как работают Tasks, async и await, и я довольно конечно, я просто слишком усложняю вещи для себя.

РЕДАКТИРОВАТЬ:

Этот вопрос возник при просмотре этого примера Metro: http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782

В частности, в MainPage.xaml.cs у них есть следующее:

var unused = Task.Factory.StartNew(async () => { // some work... });
// unused is of type Task<TResult>

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


person Justin Lang    schedule 17.07.2012    source источник
comment
Почему вы хотите написать это именно так? Весь смысл использования новых ключевых слов async/await заключался в том, чтобы вам не приходилось этого делать.   -  person Jeff Mercado    schedule 18.07.2012
comment
Похоже на плохой пример кода навскидку   -  person James Manning    schedule 18.07.2012
comment
Я сам только что посмотрел и... Вау. Да, этот официальный пример кода Windows SDK действительно плохой! Я думаю, что они полностью упустили суть async!   -  person Stephen Cleary    schedule 18.07.2012


Ответы (2)


В большинстве случаев добавление еще одного Task бесполезно, но в некоторых случаях это возможно.

Разница в том, что если вы находитесь в потоке пользовательского интерфейса (или что-то подобное) и выполняете DoSomethingAsync() напрямую, его первая часть (// do some work) также будет выполняться в потоке пользовательского интерфейса, как и любые части продолжения метода (если они не используют ConfigureAwait()) . С другой стороны, если вы запустите другой Task, и первая часть, и все последующие части DoSomethingAsync() будут выполняться на ThreadPool.

Если DoSomethingAsync() написано правильно, добавление еще одного Task не должно дать вам никаких преимуществ (и даст вам недостаток в виде дополнительных накладных расходов), но я могу представить, что есть случаи, когда это будет иметь значение.

Кроме того, вместо использования Task.Factory.StartNew() и двух await можно написать:

await Task.Run(DoSomethingAsync);
person svick    schedule 18.07.2012
comment
Хороший вопрос, я не думал о части до ожидания... +1 - person Thomas Levesque; 18.07.2012

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

Первая форма в основном эквивалентна этой:

Task<Task<MyObject>> task1 = Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
Task<MyObject>> task2 = await task1;
var myObject = await task2;

Так что это не имеет смысла: вы создаете задачу, которая просто... создает другую задачу.

person Thomas Levesque    schedule 17.07.2012
comment
Спасибо за ответ - я так и думал. Если у вас есть минутка, не могли бы вы обратиться к моему редактированию? Я немного смущен подходом, использованным в примере, на который я смотрел... - person Justin Lang; 18.07.2012
comment
@justin, я согласен с Джеймсом, это действительно плохой пример ... нет причин создавать задачу для асинхронного метода, поскольку он уже возвращает задачу - person Thomas Levesque; 18.07.2012
comment
Между ними есть разница (и я не имею в виду только накладные расходы), см. мой ответ. - person svick; 18.07.2012