2015-01-16 4 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 속성이 있습니다. 카운터가이 방법의 장점은 당신은 단지 '당신에게 한 때 Waitable 객체를 생성하지만, 될 수 있다는 것이다 0에 도달하면

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와 카운터를 만들고 콜백에서 이벤트를 재설정하는 것 카운터도 관리해야합니다.

마지막으로 또 다른 옵션은 새로운 대기열을위한 프로그래밍 추상화를 제공하는 새로운 Task-based API을 사용하는 것입니다. 지적하는

몇 가지 다른 것들 :

  • Thread.sleep를 사용하지 마십시오 - 그것은 당신의 코드를 테스트하는 데 사용할 괜찮은지하지만 당신은 당신의 비동기 코드가 작동하는 것을 확인 한 후, 사용하지 마십시오!
  • BeginInvoke 대리인에 의지하지 마십시오. 이는 진정한 병렬 처리가 아닙니다. 메소드의 호출을 단순히 연기하지만, 사용자가 생각하는대로 작동하지 않습니다. 대신, 이러한 메소드를 병렬로 실행하려면 Task, ThreadPool 또는 Thread를 사용하십시오.

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

    UPDATE 여기에 2

    방법을 실행하는 것을 :

UPDATE

당신은 또한 당신이 원래 달성을 기대하고 있었는지에 가까운 수 있습니다 루프에 대한 TPL 평행을 사용할 수 있습니다 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과 함께 사용하여 예제를 추가하겠습니다. –