2015-05-06 3 views
1

В моем коде почему QueueTasks() не запускается asyncronusly для основного метода? Есть ли другой способ позвонить, чтобы он это сделал?Запуск async() из не async без ожидания

Я хочу, чтобы QueueTasks(thingsToProcess, cts.Token); начал асинхронный метод, а затем продолжил выполнение кода.

Когда я запускаю async для google из не async, все предлагает использовать Task.Wait(), но я не хочу ждать, я просто хочу запустить процесс. Я также googled, делающий основной асинхронный поток, но нашел противоречивый совет, поэтому я не уверен, какая именно проблема здесь. Я использую .net 4.5.

class Program 
{ 
    private static SemaphoreSlim maxThreads = new SemaphoreSlim(5); 
    private static readonly object syncLock = new object(); 
    private static readonly Random getrandom = new Random(); 
    private static int inQueue = 0; 
    public static int GetRandomNumber(int min, int max) 
    { 
     lock (syncLock) 
     { // synchronize 
      return getrandom.Next(min, max); 
     } 
    } 
    static async Task DoSomething(string input, int row, SemaphoreSlim theSem) 
    { 
     theSem.Wait(); 
     inQueue++; 
     int delay = GetRandomNumber(0, 5000); 
     await Task.Delay(delay); 
     Console.WriteLine(String.Format("{0}: Doing something to {1}", row,input)); 
     inQueue--; 
     theSem.Release(); 

    } 
    static async Task QueueTasks(List<string> things, CancellationToken ct) 
    { 
      int taskNumber = 0; 
      foreach (string thing in things) 
      { 
       if (ct.IsCancellationRequested) 
       { 
        Console.WriteLine("No more tasks being queued"); 
        break; 
       } 
       else 
       { 
        maxThreads.Wait(); 
        DoSomething(thing, ++taskNumber, maxThreads); 
        maxThreads.Release(); 
       } 
      } 
    } 

    static void Main(string[] args) 
    { 

     // build list of 100 random strings to represent input 
     List<string> thingsToProcess = new List<string>(); 
     for (int i = 0; i < 100; i++) 
     { 
      thingsToProcess.Add(Path.GetRandomFileName()); 
     } 
     Console.WriteLine("Starting queue"); 

     CancellationTokenSource cts = new CancellationTokenSource(); 

     // I want this to initiate a queue starting but not stop the flow of code. 
     QueueTasks(thingsToProcess, cts.Token);   

     // This should run immediately after queue starts 
     Console.WriteLine("Hit X to stop current queue"); 
     ConsoleKeyInfo cancel = Console.ReadKey(); 

     while (cancel.KeyChar != 'x') 
     { 
      cancel = Console.ReadKey(); 
     } 

     if (cancel.KeyChar == 'x') 
     { 
      cts.Cancel(); 
      Console.WriteLine(String.Format("You requested a cancellation. {0} threads left to process", inQueue)); 
     } 
     else 
     { 
      Console.WriteLine("Operation completed without interuption"); 
     } 

     Console.ReadLine(); 
    } 
} 

ответ

4

async не является ключевым словом, что волшебным образом делает ваш метод асинхронным! Он просто позволяет вам использовать ключевое слово await внутри него, чего вы не делаете. Ваш метод полностью синхронный, поэтому он не вернется, пока не будет закончен.

Если вы использовали await в какой-то момент, то тогда QueueTasks вернется, и вы можете продолжить выполнение Main.

Кроме того, ваш код довольно небезопасен, поэтому вам повезло, что он фактически не запускается многопоточным (на самом деле он работает на нескольких потоках - но по крайней мере только около 2-3 потоков за один раз) :) Отличный стартер на многопоточном режиме - http://www.albahari.com/threading/.

Простейшая вещь, которую вы можете сделать, это просто обернуть метод QueueTasks в Task.Run. Это заставит его работать на новом потоке, параллельном вызываемому.

Второй Проще всего было бы использовать await внутри QueueTasks когда вы «ожидание» семафора - await maxThreads.WaitAsync() вместо maxThreads.Wait. Обратите внимание, что вы должны удалить ожидание внутри DoSomething - вы отбрасываете слоты семафора; на самом деле вполне возможно заблокировать ваш код, как это (все пять слотов принимаются снаружи Wait, что предотвратит Wait в DoSomething от разблокировки).

Самое сложное - научиться правильно обрабатывать очередь производителей-потребителей с параллельным исполнением и дросселированием. Опять же, http://www.albahari.com/threading/ - отличный стартер :)

+2

Спасибо! Этот учебник был действительно хорош, я прояснил много путаницы, которую я получал, просто глядя на информацию о классе на msdn. Я знал, что делаю все это неправильно, но не мог найти хорошую отправную точку для понимания того, что происходит. – Guerrilla

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