2014-11-20 2 views
3

Точно как говорится в заголовке. Интересно, я пишу асинхронный вызов и жду, когда он не понадобится.Когда асинхронно и ждут в C#?

Я видел такие методы, как это с асинхронным тегом

public async Task CreateAsync(User user) 
{ 
    if (_context.Entry<User>(user).State == EntityState.Detached) 
    { 
     _context.Set<User>().Add(user); 
    } 

    _context.Entry<User>(user).State = EntityState.Added; 

    await _context.SaveChangesAsync(); 
} 

и как это без него

public Task CreateAsync(User user) 
{ 
    if (_context.Entry<User>(user).State == EntityState.Detached) 
    { 
     _context.Set<User>().Add(user); 
    } 

    _context.Entry<User>(user).State = EntityState.Added; 

    return _context.SaveChangesAsync(); 
} 

И компилироваться. Я всегда добавляю async и жду ключевых слов и удивляюсь, может быть, если я делаю это неправильно и пишу их, когда они не нужны?

EDIT:

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

public async Task<User> CreateAsync(User user) 
{ 
    if (_context.Entry<User>(user).State == EntityState.Detached) 
    { 
     _context.Set<User>().Add(user); 
    } 

    _context.Entry<User>(user).State = EntityState.Added; 

    await _context.SaveChangesAsync(); 

    return user; 
} 

здесь еще один пример

public Task<User> FindByIdAsync(long userId) 
{ 
    return _context.Users.FindAsync(userId); 
} 

public async Task<User> FindByIdAsync(long userId) 
{ 
    return await _context.Users.FindAsync(userId); 
} 

EDIT 2

Отличных ответов до сих пор, но один последний примером. Поскольку у меня есть мои асинхронные вызовы, как бы я справился с вызовом нескольких асинхронных функций из 1 метода. вот пример того, что у меня есть, но я не знаю, правильно ли это. Я не хочу, чтобы метод завершил работу до тех пор, пока все методы AddAsync не будут завершены. Правильно ли это

private async Task AddPermissions(DataContext context) 
{ 
    var permissionService = new PermissionService(context); 

    await permissionService.AddAsync(new Permission("CanView", "View company")); 
    await permissionService.AddAsync(new Permission("CanAdd", "Add and view company")); 
    await permissionService.AddAsync(new Permission("CanEdit", "Edit and view company")); 
    await permissionService.AddAsync(new Permission("CanDelete", "Delete and view company record")); 

    await permissionService.AddAsync(new Permission("CanAdd", "Add new pages")); 
    await permissionService.AddAsync(new Permission("CanEdite", "Edit existing pages")); 
    await permissionService.AddAsync(new Permission("CanDelete", "Delete a page")); 

    await permissionService.AddAsync(new Permission("CanAdd", "Add new page content")); 
    await permissionService.AddAsync(new Permission("CanEdit", "Edit existing page content")); 
    await permissionService.AddAsync(new Permission("CanDelete", "Delete page content")); 
} 
+0

возможно дубликат [Async и ОЖИДАНИЕ] (http://stackoverflow.com/questions/14455293/async-and-await) –

ответ

3

ИМХО вам нужно будет использовать только await, если вы хотите, чтобы операция SaveChangesAsync до завершения, когда метод возвращает или вам нужно сделать что-то с результатом асинхронной операции. В этом случае вы ничего не делаете с этим, поэтому лучше не иметь метод async и избегать генерации state machine withing the method, что приводит к более эффективному коду.

Что касается второго редактирования, вы в порядке. Хотя метод будет возвращен сразу после первого await, все остальные ожидаемые операторы будут выполняться один за другим в пуле потоков, а затем результат задачи будет обновлен. Итак, если вы await AddPermissions, то этот оператор будет завершен только после завершения всех внутренних вызовов permissionService.AddAsync, если не будет выбрано исключение.

Также можно выполнить permissionService.AddAsync вызовов параллельно, при необходимости, путем сохранения возвращенных задач в списке, а затем ожидает Task.WhenAll

private async Task AddPermissions(DataContext context) 
{ 
    var permissionService = new PermissionService(context); 

    List<Task> permissionRequests = new List<Task>(); 

    permissionRequests.Add(permissionService.AddAsync(new Permission("CanView", "View company"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanAdd", "Add and view company"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanEdit", "Edit and view company"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanDelete", "Delete and view company record"))); 

    permissionRequests.Add(permissionService.AddAsync(new Permission("CanAdd", "Add new pages"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanEdite", "Edit existing pages"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanDelete", "Delete a page"))); 

    permissionRequests.Add(permissionService.AddAsync(new Permission("CanAdd", "Add new page content"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanEdit", "Edit existing page content"))); 
    permissionRequests.Add(permissionService.AddAsync(new Permission("CanDelete", "Delete page content"))); 

    await Task.WhenAll(permissionRequests); 
} 

Таким образом, каждый вызов permissionService.AddAsync Стартует запрос и добавляет соответствующую задачу к списку. После того как вы отпустили все запросы, вы можете await все их завершение с await Task.WhenAll, это будет ждать, пока они не будут завершены или не вернет ошибку. Любые исключенные исключения будут сохранены в задаче, возвращенной с Task.WhenAll. В ожидании этой задачи воссоздается первое исключение, но вы можете получить доступ ко всем из них, используя свойство Task.Excpetion, которое содержит AggregatedException, которое, в свою очередь, содержит все заброшенные исключения.

+0

Спасибо за ответ, я добавил редактирование, которое возвращает пользователя после добавления пользователя в базу данных. Вы говорите, что этот метод должен использовать ключевые слова async/wait, как я написал.Другие методы должны оставить их (хотя и неплохо, если они есть) – Gillardo

+0

С вашими изменениями я удаляю 'await', а клиент метода может ожидать результата. –

+0

отредактировал мой вопрос 1 в последний раз, не могли бы вы дать мне совет по этому поводу. Спасибо – Gillardo

0

Тема может быть глубокой, но вот обзор высокого уровня.

Существует принципиальное различие между этими двумя версиями кода вы выложили выше .. Но первый важный сходство ..

Они оба говорят _context, чтобы сохранить изменения асинхронно .. Потому что, как SaveChangesAsync .


Теперь разница ..

В первом варианте, когда вы используете async и await ключевое слово, любой код, который может быть после await вызова (в данном случае, await вызова является последним вызовом функции), компилятор превращает его в продолжение, и он должен выполняться после завершения вызова await (асинхронно). Сюда относится любая обработка исключений, которая может обернуть асинхронный вызов.

Наоборот, во второй версии, когда мы берем возвращаемое значение асинхронного вызова как Task, тогда, когда операция async была запущена, но еще не закончена, выполнение будет продолжено в этом методе (Это не превратился в продолжение компилятором). Нет кода для выполнения после операция async завершается (если вы явно не используете .ContinueWith на объекте Task).


Почему бы вам не использовать один над другим?

Опять же, на высоком уровне async и await должна будет штрафовать за обычные сценарии, где вы хотите преимущество компилятора делают некоторые магии для вас, для того, чтобы сделать его легче иметь дело с асинхронными вызовами .. Тем не менее, также менее гибкий для некоторых сценариев. Пример. Что делать, если вы хотите асинхронно запускать 10 пинговых операций, а затем писать продолжение, когда все 10 заканчиваются. То же самое невозможно с использованием async и await ключевых слов для каждого асинхронного пинга. (Первый вызов для ожидания делает остальную часть кода продолжением первого асинхронного вызова).


Поиск более в Интернете для получения более подробной информации о asyncawait .. Это может быть довольно глубоким, но стоит понимать детали.

0

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

Это в значительной степени. Я бы не стал жаловаться, если бы увидел в моей базе кода какой-либо шаблон.

0

Более простой способ будет вызывать Task.Factory.StartNew

Task.Factory.StartNew(() => new Permission("CanView", "View company")); 
Task.Factory.StartNew(() => new Permission("CanAdd", "Add and view company")); 
... 
Смежные вопросы