2

Предположим, что у меня есть действие, как показано ниже, что я хочу вернуть View asap и продолжить выполнение некоторой работы в фоновом потоке.Выполнить метод в отдельном потоке внутри Action

public async Task<ActionResult> Index() 
{ 
    Debug.WriteLine("Inside Index"); 

    var newCustomer = new Customer 
    { 
     Name = "Ibrahim" 
    }; 

    Task.Run(() => SaveCustomer(newCustomer)); 

    Debug.WriteLine("Exiting Index"); 

    return View(); 
} 

private async Task SaveCustomer(Customer NewCustomer) 
{ 
    Debug.WriteLine("Started Saving Customer"); 

    await Task.Delay(2000); 

    Debug.WriteLine("Completed Saving Customer"); 
} 

я получаю выход, как предполагалось, который:

Inside Index 
Exiting Index 
Started Saving Customer 
Completed Saving Customer 

Но что меня беспокоит то, что я получаю предупреждение, что мое Index действие будет работать синхронно, независимо, и я должен положить await, но затем представление возвращается после завершения SaveCustomer, и цель побеждена.

Как я это делаю неправильно? Любое предложение приветствуется.

+1

может быть немного не по теме - но что, если 'SaveCustomer (newCustomer)' терпит неудачу? Разве текущий запрос не должен знать об этом? –

+0

@shay__ Да, конечно. Но это всего лишь пример. Я просто хочу знать, правильно ли я хочу это делать или нет. – lbrahim

+0

Может быть, например, механизм ведения журнала, а не для сохранения клиента. – lbrahim

ответ

1

Ваш Index не использует никакой асинхронной функции вообще. Почему вы отметили его async? Вы должны что-то недопонимать, не знаете, что. Удалите спецификацию async Task.

+0

Непонимание заключается в том, что я где-то читал, что для обработки HTTP существуют ограниченные зарезервированные потоки, поэтому, если действия не являются асинхронными и блокируются, то в конце концов не будет ни одного потока с пометкой «Индекс» как асинхронный для начала. Это неправильно? Может быть, здесь не применимо? – lbrahim

+1

Отметить его как асинхронный, ничего не делать, чтобы освободить поток. Если бы это было так, все методы всегда были бы асинхронными. async в значительной степени просто позволяет ключевое слово ожидания. Слушайте, вероятность 99%, что вам не нужен async IO в любом случае (в ASP.NET). На протяжении десятилетий мы запускали наши серверы без async IO, в основном. Убедитесь, что вы понимаете, для чего это необходимо, и почему перед его использованием. – usr

+1

Обычно я предоставляю следующие ссылки: http://stackoverflow.com/a/25087273/122718 Почему учебник EF 6 использует асинхронные вызовы? http://stackoverflow.com/a/12796711/122718 Должны ли мы переключиться на использование async I/O по умолчанию? – usr

1

Вы получаете предупреждение о компиляторе, потому что в вашем методе Index() нет ничего асинхронного. Ваша линия Task.Run(() => SaveCustomer(newCustomer)); означает «Огонь и забыть» (не ожидаемая задача) - это совсем не то, что асинхронный код. Index() полностью синхронно, одновременно создавая «боковую задачу» для выполнения в будущем. Как упоминалось в другом ответе, вы можете просто удалить асинхронную метку из своего метода - это не async.

+0

Итак, действие 'Index' на самом деле не блокируется, и' async' не нужен? – lbrahim

+0

@lbrahim правильно, нет ничего блокирующего в вашем ** примере **. Но опять же, это просто пример, не так ли? Разве ваш реальный код не вызвал бы вызовы ввода-вывода? –

2

Но что беспокоит меня то, что я получаю предупреждение, что мой индекс действия будет работать синхронно

Как я это делаю не так?

Не заставляйте асинхронность сверху вниз. Вместо этого начните с естественно-асинхронных операций на самом нижнем уровне (например, доступ к базе данных EF6) и позвольте асинхронности расти с самого низкого уровня кода вверх.

Кроме того, на ASP.NET вам следует избегать Task.Run.

Применение этих двух принципов приводит к Index метода, как это:

public async Task<ActionResult> Index() 
{ 
    Debug.WriteLine("Inside Index"); 

    var newCustomer = new Customer 
    { 
    Name = "Ibrahim" 
    }; 

    await SaveCustomer(newCustomer); 

    Debug.WriteLine("Exiting Index"); 

    return View(); 
} 

но тогда вид возвращается после SaveCustomer завершается и цель побеждена.

Совсем нет. Цель асинхронного кода ASP.NET: не, чтобы вернуться к клиенту. async и await не изменяют протокол HTTP. await на стороне сервера дает пул потоков, а не клиент.

Если вы потребность вернуться рано (и большинство людей не - они только думают они «необходимость» в), то вы должны использовать one of the established patterns for returning early (как я описал в моем блоге). Обратите внимание, что единственное правильное (то есть полностью надежное) решение влечет за собой создание надежной очереди с независимым фоновым процессом.

+1

OP - вы должны прочитать этот ответ снова и снова, пока не получите его ... все там. –

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