推迟代码执行的最佳方法是什么?
我有许多相互调用的方法,每个方法都必须执行某些任务,其中一些是异步的,所有这些都在 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 访问,这是昂贵的。
在这些情况下我可以使用其他方法来推迟代码执行吗?推荐的方法是什么?
I have many methods calling each other that each have to certain tasks, some of them asynchronous, that all operate on a DOM (so only one thread must access the DOM at any time).
For example:
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...*/
}
}
Now let's say I have a method that wants to execute method A() 1000 times as fast as possible (the async methods can run in separate threads, however all other code must only access the DOM one at a time), so Ideally when the async calls are reached code execution for A(), B() and C() are paused, so A() can be called again.
There are 2 ways I can think of to do this. One is with yield, by changing all the methods to iterators I can pause and resume execution:
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.
}
This method has quite some overhead from the iterators, and is a bit more code intensive, however it all runs on one thread so I don't need to synchronize the DOM access.
Another way would be to use threads (1000 simultaneous threads are a bad idea, so i'd implement some kind of thread pooling), but this requires synchronizing DOM access which is costly.
Are there any other methods I can use to defer code execution under these conditions? What would be the recommended way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如 Karl 所建议的,这需要多线程吗? 我可能会选择多线程情况
现在在这种情况下,我会考虑使用线程池来多次启动 A 并同步对 DOM 的访问。使用线程安全缓存可以降低 DOM 同步的成本 - 当然这取决于某种 DOM 访问。
As Karl has suggested, does this need to be multi-threaded? I may go for multi-threaded situation if
Now in such case, I would consider using a thread pool to launch A multiple times with synchronizing access to DOM. Cost of DOM synchronization can be reduced using thread-safe caching - of course that depends upon a kind of DOM access.