2016-01-07 5 views
1

Я много гулял и читал разные учебники noob, но я не думаю, что понимаю, что нужно делать. В основном существует существующий код, который является синхронным, что делает что-то, если сервер запущен и работает. Иногда, очень редко, сервер занимает больше времени, поэтому я хотел бы включить его в некоторую логику повтора. Я построил совершенно глупое приложение консоли, чтобы попытаться понять, как асинхронные и жду работать немного и придумал это:Изменение синхронного метода для async

private static int counter = 0; 

    static void Main(string[] args) 
    { 
     DoIt(); 
     Console.ReadLine(); 
    } 

    static bool LongTask() 
    { 
     if (counter == 2) 
     { 
      Console.WriteLine("finally true"); 
      Thread.Sleep(1000); 
      return true; 
     } 
     counter++; 
     Console.WriteLine("false"); 
     Thread.Sleep(1000); 
     return false; 
    } 

    public static Task<bool> WrapperLongTask() 
    { 
     Console.WriteLine("wrapper called"); 
     return Task.Run(() => LongTask());    
    } 

    public static async Task DoIt() 
    { 
     Console.WriteLine("hi"); 
     var result = await WrapperLongTask(); 
     while (result != true) 
     { 
      result = await WrapperLongTask(); 
      Console.WriteLine("inside while loop"); 
     } 
     Console.WriteLine($"outside while loop {result}"); 
     Console.WriteLine("bye"); 
    } 

Моей функция LongTask будет представлять свою текущую функцию, которая делает работу, которая обычно работает в первый раз. Это нормально практика затем вызвать этот метод с

Task.Run(() => LongTask()) 

Если предположить, что это «нормально», то я бы в принципе создать это в моем фактический код для моего текущего метода DoWork().

Task DoWorkAsync(....) { 
    return Task.Run(() => DoWork() 
} 

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

var x = await DoWorkAsync; 
// do more stuff with x 

Это способ, которым я должен преобразовать предыдущий метод синхронизации асинхр? Заранее спасибо.

Edit:

псевдо-код для DoWork (каталог строка, CancellationToken маркер)

var files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); 
foreach (var file in files) { 
    try { 
     token.ThrowIfCancellationRequested(); 
     var fileName = Path.GetFileName(file); 
     // check if file already exists on server, if not, upload it 
    } 
    catch (Exception exception) { 
     // error handling 
    } 
} 
+0

Что это «делает что-то»? Вам нужно ждать результатов до того, как сервер сделает что-нибудь еще? Призывает ли он какие-либо методы, имеющие асинхронные эквиваленты? Что еще делает сервер? (Это веб-приложение ASP.NET или что-то еще)? В зависимости от того, какие ответы на эти вопросы, в частности последний, я могу посоветовать по-другому или, возможно, вы вообще не беспокоитесь о асинхронности. –

+0

Не могли бы вы разместить свой «настоящий» код, чтобы мы могли видеть, как он может быть асинхронным? –

ответ

2

Короткий ответ Нет, вы не можете конвертировать все типы синхронного кода асинхронным просто оборачивать операции с Task.Run и сделать метод возврата Task.

Как правило, асинхронный код имеет смысл, когда рассматриваемая операция может вызывать некоторые операции ввода-вывода (чтение/запись файловой системы, сетевой или веб-доступ, доступ к базе данных и т. Д.).

Например, если у вас есть метод, который считывает некоторые данные из файла с использованием синхронных методов, таких как FileStream.Read, а затем некоторые из них работают над содержимым такого файла, вы можете преобразовать свой метод в асинхронный, invoke FileStream.ReadAsync, а затем асинхронно дождитесь, пока ReadAsync будет выполняться с помощью ключевого слова await, а затем работать с содержимым файла (конечно, вы должны изменить метод, чтобы вернуть Task и быть async).

Преимущество в этом случае заключается в том, что нет потока, ожидающего завершения операции ввода-вывода, и потоки дороги.

Преимущество отсутствия потоков, ожидающих завершения операций ввода-вывода, очень важно в серверных приложениях, таких как веб-сайты ASP.NET, где вы ожидаете много одновременных запросов. Однако для простых приложений вы, возможно, не захотите беспокоиться о асинхронном коде.

Вы можете использовать Task.Run, если хотите выполнить несколько интенсивных операций с ЦП на нескольких ядрах ЦП.

Например, если у вас есть 4 ядра процессора, имеет смысл создать 4 задания через Task.Run для обработки некоторых данных.Рассмотрим предыдущий пример, после того как вы асинхронно дождитесь завершения ReadAsync, вы можете разделить результат чтения на 4 части (при условии, что данные относительно большие) и создать 4 задания через Task.Run, каждый из которых будет обрабатывать одну часть результатов , Затем вы можете асинхронно дождаться завершения 4 задач с помощью Task.WhenAll.

+0

Если вы выполняете работу с ЦП на больших последовательностях, имеет смысл использовать 'Parallel.ForEach', чем задачи. Он будет выполнять распределение входных данных и балансировку нагрузки лучше, чем «разделить последовательность на N частей». –

+0

Правильно. Я использовал 'Task.Run', потому что я хотел дать OP пример того, когда он может быть использован. Также обратите внимание, что (AFAIK) вы не можете асинхронно ждать завершения 'Parallel.ForEach'. Он блокирует текущий поток, пока все операции не будут завершены. –

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