2015-01-16 3 views
-1

В настоящее время я использую делегат для создания асинхронных вызовов в цикле for, проблема, с которой я сталкиваюсь, - как узнать, когда эти асинхронные вызовы завершены?Асинхронные вызовы с делегатом

, например:

  public delegate string GetMergeSectionCaller(string something1, out int threadId); 

     public Dataset GetDataset (param1, param2) { 
       int threadId; 
       Dataset ds = new Dataset; 

       using (myConnection) { 
        myConnection.StartConnection(); 
        GetMergeSectionCaller caller = new GetMergeSectionCaller(GetMergeSection); 
        foreach (var r in anObjectList) { 
         IAsyncResult result = caller.BeginInvoke(r.ToString(), out threadId, null, null); 
        } 

        //I want to do here is wait for the above every single foreach BeginInvoke to finish; then do the below job 
        ds = GetFinalData(); 
       } 
       //do more thing to ds here; 
       return ds; 
      } 

     public void GetMergeSectionCaller(string something1, out int threadId) { 
      //doing superlong long job 
      //in my actual case, it's actually inserting data to db etc 

      Thread.Sleep(5000); 
      threadId = Thread.CurrentThread.ManagedThreadId; 
     } 

, так что я пробовал различные подходы; такие как передача обратного вызова к моему BeginInvoke и EndInvoke там, но все же - мне не хватает способа остановить остальную часть кода, чтобы запустить, прежде чем я смог закончить foreach;

Возможно, мне не хватает чего-то довольно простого? ... Может ли кто-нибудь, пожалуйста, показать мне полный рабочий образец, основанный на моем состоянии?

+0

Упомянуть, какой язык программирования это поможет. – JJJ

+0

просто редактирование названия: в C# – nerrad

ответ

2

У вас есть несколько вариантов. IAsyncResult имеет свойство WaitHandle, которое вы можете использовать для ожидания.

var results = new List<WaitHandle>(); 
foreach (var r in anObjectList) { 
    results.Add(caller.BeginInvoke(r.ToString(), out threadId, null, null).WaitHandle); 
} 
// wait for all results to complete 
WaitHandle.WaitAll(results.ToArray()); 

Другим вариантом было бы создать ManualResetEvent и счетчик и сбросить событие от обратного вызова, когда счетчик достигнет 0. Преимущество этого метода заключается в том, что вы будете создавать только один waitable объект, но вы» d должен также управлять счетчиком.

И, наконец, другим вариантом было бы использовать новый Task-based API, который обеспечивает гораздо лучшую абстракцию программирования для ожидания задач.

Некоторые другие вещи укажут:

  • НЕ используйте Thread.Sleep - это нормально, чтобы использовать его, чтобы проверить свой код, но как только вы убедились, что ваш асинхронный код работает, не используйте его!
  • НЕ полагайтесь на делегата BeginInvoke - это не истинный параллелизм. Он просто отменяет вызов метода, но он не делает то, что вы думаете, что он делает. Вместо этого, если вы хотите параллельно выполнять эти методы, используйте либо задачу, ThreadPool, либо Thread.

UPDATE

Вы можете также использовать параллельно TPL для петли, которая могла бы быть ближе к тому, что вы изначально рассчитывали достичь:

Parallel.ForEach(anObjectList, anObjectItem => { 
    // do something with anObjectItem 
}); 
// this parallelizes the for-loop iterations 

UPDATE 2

Вот как запустить задачи с использованием рабочих потоков из ThreadPool и ManualResetEvent.

ManualResetEvent mreComplete = new ManualResetEvent(false); 
int callsRemaining; 

GetMergeSectionCaller caller = new GetMergeSectionCaller(GetMergeSection); 
callsRemaining = anObjectList.Count; 
mreComplete.Reset(); 
foreach (var r in anObjectList) { 
    ThreadPool.QueueUserWorkItem((Action)delegate { 
     caller(r.ToString()); 
     lock{ 
      if(--callsRemaining==0) mreComplete.Set(); 
     } 
    } 
} 
mreComplete.Wait(); 
+0

woot woot !! большое спасибо!! Я на самом деле пробовал все из тех, кого вы упомянули, но не знал, что я могу сделать waitHandle, как в списке. Я тестировал и отлично работал! С другой стороны, мне интересно узнать, как использовать ManualResetEvent? Я пробовал с этим хорошо, прежде чем прыгать в stackoverflow для справки, но не повезло; и да! Я тестировал Parallel.ForEach для моего последнего случая, если я не получу здесь никакой помощи, еще раз спасибо! – nerrad

+0

Я добавлю пример с ManualResetEvent в сочетании с TreadPool. –

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