我有许多相互调用的方法,每个方法都必须执行某些任务,其中一些是异步的,它们都在 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 访问,这是昂贵的。
在这些条件下,我可以使用其他方法来推迟代码执行吗?推荐的方法是什么?