2016-03-14 3 views
1

Так вот у меня есть функцияКогда использовать «async» вместо того, чтобы возвращать новую задачу Task.Run?

static bool Login(SignupData sd) 
{ 
    bool success=false; 
    /* 
     Perform login-related actions here 
    */ 
} 

И есть еще одна функция

static Task<bool> LoginAsync(SignupData sd) 
{ 
    return Task.Run<bool>(()=>Login(sd)); 
} 

Теперь, я наткнулся на несколько иной реализации этой модели, где вы бы добавить async ключевое слово функция, которая возвращает Task<TResult> (чтобы она выглядела так: async Task<TResult> LoginAsync(SignupData sd)). В этом случае, даже если вы вернете TResult вместо Task<TResult>, программа все еще компилируется.

Мой вопрос здесь, какую реализацию следует предпочесть?

static Task<bool> LoginAsync(SignupData sd) 
{ 
    return Task.Run<bool>(()=>Login(sd)); 
} 

ИЛИ этот?

async static Task<bool> LoginAsync(SignupData sd) 
{ 
    bool success=Login(sd); 
    return success; 
} 
+1

переведите свой вопрос в код обзора обмена столами –

+0

@KevinAvignon Пожалуйста, ознакомьтесь с правилами обзора кода, прежде чем предлагать отправлять вопросы там. – hvd

+2

Вы должны получить предупреждение компилятора для второго метода. И ни одна из реализаций не является хорошей. Если вы не можете предоставить действительно асинхронный метод, просто не предоставляйте его. Вызывающий может всегда выполнять «Task.Run». –

ответ

7

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

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

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


То есть, я бы рекомендовал искать способ, чтобы создать LoginAsync реализацию, которая действительно асинхронно. Если он загружает данные из базы данных, например, откройте соединение с помощью OpenAsync, извлеките данные, используя ExecuteReaderAsync. Если он подключается к веб-службе, подключитесь с помощью асинхронных методов для любого используемого протокола. Если он регистрируется каким-либо другим способом, сделайте все, что вам нужно, чтобы сделать , что асинхронный.

Если вы придерживаетесь такого подхода, ключевые слова имеют идеальный смысл и могут сделать такую ​​реализацию очень простой в создании.

+0

Как это аргумент * против * 'async' (или задачи, игнорируя выбор Run) в качестве композиции? – user2864740

+0

@ user2864740 Либо я не понимаю ваш вопрос, либо не вижу, как он относится к моему ответу. Можете ли вы уточнить? – hvd

+0

Является ли 'IHttpClient {Задача GetAsync (путь Uri); } 'действительный интерфейс? – user2864740

0

В то время как HVD верен, я буду погружаться в async, пытаясь описать его предполагаемое использование.

Ключевое слово async и ключевое слово сопровождающего ожидания - это метод ярлыков для реализации шаблонов неблокирующего кода в вашем приложении. Хотя он отлично сочетается с остальной частью параллельной библиотеки задач (TPL), он обычно не используется совершенно одинаково. Красота - это элегантность того, как компилятор переплетается в асинхронности, и позволяет обрабатывать его без явного разворота отдельных потоков, что может быть или не быть тем, что вы хотите.

Для примера, давайте посмотрим на код:

async static Task<bool> DoStuffAsync() 
{ 
    var otherAsyncResult = doOtherStuffAsync(); 

    return await otherAsyncResult 
} 

Смотрите AWAIT ключевое слово?Он говорит, вернитесь к вызывающему, продолжайте, пока мы не получим результат, который вам нужен. Не блокируйте, не используйте новый поток, но в основном возвращайтесь с обещанием результата при готовности (A Task). Затем вызывающий код может продолжать и не беспокоиться о результате до тех пор, пока он не появится.

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

Лучший способ обработки кода - сделать синхронный вызов кодов асинхронным и ждать его. Таким образом, вы будете как можно больше асинхронны. Всегда лучше всего закрепить этот уровень как можно выше в вашем приложении, насколько это возможно, вплоть до пользовательского интерфейса.

Надейтесь, что сделал смысл. TPL - это огромная тема, и Async/Await действительно добавляет некоторые интересные способы структурирования вашего кода. https://msdn.microsoft.com/en-us/library/hh191443.aspx

Смежные вопросы