2015-06-15 2 views
3

Я реализую метод интерфейса, который является асинхронным (возвращает задачу). Однако моя реализация по необходимости является синхронной. Каков наилучший способ сделать это? Есть ли встроенный способ сделать это? Вот несколько вариантов, я рассматриваю:Каков наилучший способ обернуть синхронный код как задачу async?

  • Вариант 1: Task.FromResult

    return Task.FromResult(ComputeResult()); 
    

Это хорошо, потому что мой код работает синхронно. Недостатком является то, что если ComputeResult() терпит неудачу или отменен, мой метод бросает вместо возврата неудавшейся задачи.

  • Вариант 2: Task.Run

    return Task.Run(() => ComputeResult()); 
    

Это распространяется отказ и аннулирование более естественно. Однако это также вводит ненужный поток-хоп.

  • Вариант 3: TaskCompletionSource

    var tcs = new TaskCompletionSource<T>(); 
    try 
    { 
        tcs.SetResult(ComputeResult()); 
    } 
    catch (OperationCanceledException) 
    { 
        tcs.SetCanceled(); 
    } 
    catch (Exception ex) 
    { 
        tcs.SetException(ex); 
    } 
    
    return tcs.Task; 
    

Это и распространяется отказ/отмена и исключает нить-хоп, но это более многословным и сложным.

+0

Проверьте некоторые ответы на [этот вопрос] (http://stackoverflow.com/questions/28929647/to-task-run-or-not-to-task-run). –

+1

Только второй вариант фактически асинхронен для вызывающего. Вопрос в том, насколько плохим является блокирование вызывающего потока. Предположительно, интерфейс использует задачи, чтобы вызывающий абонент не блокировался. –

+0

что вы подразумеваете под «нить-хоп»? –

ответ

2

Две другие опции, которые вы могли упустить из виду:

  • просто сделать свой метод async и сделать return ComputeResult(). Подавить предупреждение компилятора pragma. Если вам не нравится, чтобы подавить предупреждение, вы можете сделать это:

    async Task<Result> ComputeResultAsync() 
    { 
        await Task.FromResult(0); 
        return ComputeResult(); 
    } 
    
  • Task.RunSynchronously использование:

    Task<Result> ComputeResultAsync() 
    { 
        var task = new Task<Result>(() => ComputeResult()); 
        task.RunSynchronously(TaskScheduler.Default); 
        return task; 
    } 
    

Последнее обеспечит распространение исключений аналогично методу async. Обратите внимание, однако, under certain conditions (например, когда он слишком глубок в стеке), RunSynchronously все равно может выполняться асинхронно.

+0

Вы живы! ; p –

+1

@YuvalItzchakov, я всегда был, по крайней мере, в режиме только для чтения :) Это не значит, что я неактивен. Просто когда я собираюсь что-то публиковать, обычно есть качественный ответ! – Noseratio

+1

Определенно. Сообщество выросло :) –

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