推迟代码执行的最佳方法是什么?

时间:2010-08-10 09:37:47

标签: c# .net multithreading yield deferred-execution

我有很多方法相互调用,每个方法都需要执行某些任务,其中一些是异步的,所有任务都在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()。

我有两种方法可以做到这一点。一个是yield,通过将所有方法更改为迭代器,我可以暂停并继续执行:

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访问,这是昂贵的。

我是否可以使用其他方法来推迟在这些条件下执行代码?建议的方法是什么?

1 个答案:

答案 0 :(得分:1)

正如Karl所说,这需要多线程吗?如果

,我可能会选择多线程的情况
  1. DOM访问是随机的但不常见
  2. A,B,C中的所有其他代码在时间方面都很重要(与DOM访问代码相比)
  3. A,B,C中的所有其他代码都可以以线程安全的方式执行,无需执行任何锁定等,即如果它们依赖于某些共享状态,那么您可以同步访问它。
  4. 现在在这种情况下,我会考虑使用线程池多次启动A并同步访问DOM。使用线程安全缓存可以降低DOM同步的成本 - 当然这取决于一种DOM访问。