2017-02-14 3 views
3

В приложении ASP.NET 4.5, какой из них лучше для вызова метода async из метода синхронизации?Task.Run vs null SynchronizationContext

var result = Task.Run(() => SomethingAsync()).GetAwaiter().GetResult(); 

// or 

var temp = SynchronizationContext.Current; 
try 
{ 
    SynchronizationContext.SetSynchronizationContext(null); 
    return SomethingAsync().GetAwaiter().GetResult(); 
} 
finally 
{ 
    SynchronizationContext.SetSynchronizationContext(temp); 
} 

Примечание: Да, я знаю, что я должен использовать async/await весь путь вниз, но я спрашиваю о том самом дне, так и вне ASP.NET Ядра фильтров и виды бритвенные не ASync , поэтому, если я хочу вызвать метод async из фильтра или вида бритвы, мне нужно каким-то образом синхронизировать его. Просто используя SomethingAsync().GetAwaiter().GetResult() приводит к тупику, из-за SynchronizationContext, поэтому мне нужен способ запускать этот код без SynchronizationContext.

EDIT Вот простой вспомогательный класс, который оборачивает это до чисто:

public static class Async 
{ 
    public static T Run<T>(Func<Task<T>> func) 
    { 
     var context = SynchronizationContext.Current; 
     if (context == null) 
     { 
      return func().GetAwaiter().GetResult(); 
     } 

     SynchronizationContext.SetSynchronizationContext(null); 

     try 
     { 
      return func().GetAwaiter().GetResult(); 
     } 
     finally 
     { 
      SynchronizationContext.SetSynchronizationContext(context); 
     } 
    } 

    public static void Run(Func<Task> func) 
    { 
     var context = SynchronizationContext.Current; 
     if (context == null) 
     { 
      func().GetAwaiter().GetResult(); 
      return; 
     } 

     SynchronizationContext.SetSynchronizationContext(null); 

     try 
     { 
      func().GetAwaiter().GetResult(); 
     } 
     finally 
     { 
      SynchronizationContext.SetSynchronizationContext(context); 
     } 
    } 
} 

// Example 
var result = Async.Run(() => GetSomethingAsync("blabla")); 
+0

Подход 'Task.Run' немного более корректен, а подход' SynchronizationContext.Current' немного более эффективен. Какой из них «лучше» - это просто вопрос мнения. –

+0

Я должен был сказать «лучше». Хорошо, мне кажется, что во втором случае нет ничего плохого, поэтому, если он завернут в хорошую статическую функцию, похоже, что должно быть хорошо использовать – Marius

+0

Вам не нужно проверять 'if'. 'SetSynchronizationContext (null)' действительно. –

ответ

1

Очевидно, что это не является идеальным для вызова кода асинхронной синхронно, однако, если вы должны, я бы сказал, избежать Task.Run, если вы можете Помоги.

Task.Run имеет целый ряд вопросов по SetSynchronizationContext(null):

  • Это не ясно, почему вы используете его, вы хотите, чтобы начать новую задачу на веб-сервере? Это будет удалено новыми разработчиками быстро, если комментариев нет. А потом бум, трудно диагностировать производственные проблемы (тупики).
  • Он начинается с нового потока пула потоков, когда ему это не нужно, пока он не достигнет своего первого ожидания завершенного продолжения, и работает синхронно. (это очень незначительная оптимизация)
  • Если вы делаете это с нескольких уровней, чтобы защитить свой SynchronizationContext, он блокирует синхронно для всей функции возврата задачи, а не только для области, в которой она нуждается, вы также умножаете свою проблему каждый раз, когда вы его используете. Вы закончите с дольше, блокируя асинхронный код, это, конечно, не то, что вы хотите.
  • Если выяснилось, что блокировки/тупика не было, как вы считали, было или исправлено, то теперь Task.Run вводит блокировку через async, тогда как SetSynchronizationContext(null) не будет вам ничего стоить.

Наконец, альтернативное предложение - use something like AsyncPump.Run (Stephen Toub), когда вы блокируете функцию возврата Task. Он ждет так, что очереди в очереди запускаются блокирующим потоком, так что вы не платите цену за несколько параллельных потоков, и вы не получаете никаких взаимоблокировок, очевидно, все еще не так хорошо, как просто использовать async полностью.

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