2010-08-10 5 views
0

나는 각각이 특정 작업 (비동기 중 일부)을 가지고 서로를 호출하는 방식을 많이 가지고 있는데, 모두 비동기식이므로 모든 것이 DOM에서 작동하기 때문에 (단 하나의 스레드 만 언제든지 DOM에 액세스해야한다).코드 실행을 지연시키는 가장 좋은 방법은 무엇입니까?

예를 들어

: 이제

object A() { 
    /*...A() code 1...*/ 
    var res = B(); 
    /*...A() code 2 that uses res...*/ 
} 

object B() { 
    /*...B code 1...*/ 
    var res1 = C(); 
    /*...B code 2 that uses res1...*/ 
    var res2 = C(); 
    /*...B code 3 that uses res2...*/ 
} 

object C() { 
    /*...C code 1...*/ 
    if (rnd.NextDouble() < 0.3) { // unpredictable condition 
     startAsyncStuff(); 
     /*...C code 2 that uses async result above...*/ 
    } 
    if (rnd.NextDouble() < 0.7) { // unpredictable condition 
     startOtherAsyncStuff(); 
     /*...C code 3 that might use any/both async results above...*/ 
    } 
} 

의 나는 방법 A를 (실행하고자하는 방법이 있다고 가정하자) 1000 배 가능한 한 빨리 (비동기 방법 그러나, 별도의 스레드 다른 모든를 실행할 수 있습니다 코드는 한 번에 하나씩 만 DOM에 액세스해야 함) 이상적으로 비동기 호출에 도달하면 A(), B() 및 C()에 대한 코드 실행이 일시 중지되므로 A()를 다시 호출 할 수 있습니다.

내가 할 수있는 두 가지 방법이 있습니다.

struct DeferResult { 
    public object Result; 
    public bool Deferred; 
} 

IEnumerator<DeferResult> A() { 
    /*...A() code 1...*/ 
    var dres = B(); 
    if (dres.Deferred) yield dres; 
    /*...A() code 2...*/ 
} 

IEnumerator<DeferResult> B() { 
    /*...B code 1...*/ 
    var dres1 = C(); 
    if (dres1.Deferred) yield dres1; 
    /*...B code 2...*/ 
    var dres2 = C(); 
    if (dres2.Deferred) yield dres2; 
    /*...B code 3...*/ 
} 

IEnumerator<DeferResult> C() { 
    /*...C code 1...*/ 
    if (rnd.NextDouble() < 0.3) { // unpredictable condition 
     startAsyncStuff(); 
     yield return new DeferResult { Deferred = true; } 
     /*...C code 2 that uses async result above...*/ 
    } 
    if (rnd.NextDouble() < 0.7) { // unpredictable condition 
     startOtherAsyncStuff(); 
     yield return new DeferResult { Deferred = true; } 
     /*...C code 3 that might use any/both async results above...*/ 
    } 
    yield return new DeferResult { Result = someResult(); } 
} 

void Main() { 
    var deferredMethods = new List<IEnumerator<DeferResult>>(); 
    for (int i = 0; i < 1000; i++) { 
     var en = A().GetEnumerator(); 
     if (en.MoveNext()) 
      if (en.Current.Deferred) 
       deferredMethods.Add(en); 
    } 
    // then use events from the async methods so when any is done continue 
    //  running it's enumerator to execute the code until the next async 
    //  operation, or until finished 
    // once all 1000 iterations are complete call an AllDone() method. 
} 
  • 이 방법은 반복자에서 꽤 많은 오버 헤드를 가지고 있으며, 조금 더 많은 코드를 많이하지만 모든 : 하나는 반복자에 대한 모든 방법을 변경하여 I 일시 중지 및 실행을 재개 할 수 있습니다, 수율이다 하나의 스레드에서 실행되므로 DOM 액세스를 동기화 할 필요가 없습니다.

  • 또 다른 방법은 스레드를 사용하는 것입니다 (1000 개의 동시 스레드는 나쁜 아이디어이므로 스레드 풀링의 일종을 구현할 수 있습니다). 그러나 이것은 비용이 많이 드는 DOM 액세스를 동기화해야합니다.

이러한 조건에서 코드 실행을 지연시키는 데 사용할 수있는 다른 방법이 있습니까? 이 작업을 수행하는 데 권장되는 방법은 무엇입니까?

+0

나는 자물쇠가 그것을 할 것이라고 생각합니다. 그리고 폴링 작업의 경우 .Net 4.0 또는 ThreadPoll을 사용하는 경우 Task Parallel Library에서 빌드를 사용하십시오. –

+0

동의하지만 설계 변경을 고려하고 싶을 수 있습니다. 왜 멀티 스레드를 원합니까? DOM에 대한 액세스를 직렬화하므로 한 번에 하나의 스레드 만 액세스 할 수 있으므로 스레드의 이점이 느슨해집니다. –

답변

1

Karl이 제안했듯이 멀티 스레딩해야합니까?

  1. DOM 액세스가 임의하지만 자주하지 않으면 나는 멀티 스레드 상황에 갈 수
  2. A, B의 다른 모든 코드, C는 (DOM 액세스 코드에 비해) 시간의 측면에서 상당한입니다
  3. A, B, C의 다른 모든 코드는 모든 잠금 등을 수행하는 스레드 안전 모드에서 실행될 수 있습니다. 즉, 일부 공유 상태에 의존하는 경우 해당 액세스를 동기화 할 수 있습니다.

그런 경우에는 스레드 풀을 사용하여 DOM에 대한 액세스를 동기화하여 여러 번 시작할 수 있습니다. DOM 동기화 비용은 thread-safe 캐싱을 사용하여 줄일 수 있습니다. 물론 DOM 액세스의 종류에 따라 다릅니다.

관련 문제