У меня есть много методов, вызывающих друг друга, которые у каждого есть для определенных задач, некоторые из них асинхронные, которые все работают на 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, что является дорогостоящим.
Существуют ли другие методы, которые я могу использовать для отсрочки выполнения кода в этих условиях? Каков был бы рекомендуемый способ сделать это?