2010-08-10 113 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. 
} 
  • 這種方法有從迭代器相當一些開銷,而且是更多的代碼密集,然而這一切在一個線程上運行,所以我不需要同步DOM訪問。

  • 另一種方法是使用線程(1000個併發線程是一個壞主意,所以我會實現某種線程池),但這需要同步DOM訪問,這是昂貴的。

有沒有其他方法可以用來在這些條件下推遲代碼執行?推薦的方法是什麼?

+0

我認爲鎖會做到這一點。如果您使用.Net 4.0或其他ThreadPoll,則任務輪詢使用Task Parallel Library中的內部版本。 – 2010-08-10 09:41:11

+0

我同意,但您可能需要考慮設計更改。爲什麼你會想要這個多線程呢?您將序列化訪問DOM,因此一次只有一個線程可以訪問它,並且您失去了線程的好處。 – 2010-08-10 18:30:03

回答

1

正如Karl所說,這是否需要多線程?我可以去多線程的情況下,如果

  1. DOM訪問是隨機的,但不頻繁
  2. 在A,B的所有其他代碼,C(相對於DOM接入代碼)是在時間上大幅
  3. A,B,C中的所有其他代碼都可以以線程安全的方式執行,而不用執行任何鎖定等,也就是說,如果它們依賴於某種共享狀態,那麼您已同步訪問以及。

現在在這種情況下,我會考慮使用線程池多次啓動A,同時訪問DOM。使用線程安全緩存可以降低DOM同步的成本 - 當然這取決於一種DOM訪問。

相關問題