简体   繁体   English

中断事件循环处理而不中断循环

[英]Break for event loop processing without breaking loop

I found myself trying to process a vast amount of data recently and I had to do some (lets call it) creative coding to get the desired result.我发现自己最近试图处理大量数据,我不得不做一些(让我们称之为)创造性的编码来获得所需的结果。

I knew the processing would be a multi day task so I wrote it in a way that could be interrupted and resumed.我知道处理将是一项多天的任务,所以我以一种可以中断和恢复的方式编写它。 But what stumped me was finding a nice way to process SIGINT/SIGTERM style events without wanting to break my loop.但是让我难受的是找到了一种很好的方法来处理 SIGINT/SIGTERM 风格的事件,而不想打破我的循环。

btw these are obviously not the real names for my functions顺便说一句,这些显然不是我函数的真实名称

let closed = false;
function* syncGenerator() {
  yield* ~20-trillion-calculated-results;
}
function main() {
  try {
    for ( const value of syncGenerator() ) {
      syncWork(value);
      if (closed) {
        syncGracefulCleanup();
        break;
      }
    }
  } catch ( err ) {
    handleError(err);
  } finally {
    syncGracefulCleanup2();
  }
}
process.on('SIGINT', () => closed = true);

I had failed to realise that SIGINT would never be processed while I was still in the for-loop and so would only ever finish after the entire dataset was processed (a very foolish oversight, I think I was deluded to believing it would work the same was as Arduino Hardware Interrupts. D'oh. Lesson learned.我没有意识到 SIGINT 在我还在 for 循环中时永远不会被处理,所以只有在整个数据集被处理后才会完成(一个非常愚蠢的疏忽,我想我被迷惑了相信它会工作相同就像 Arduino 硬件中断一样。天啊。吸取了​​教训。

Now that I realised this, my solution was to put half of my code at the end of the tick using the microtask async-await trick.现在我意识到了这一点,我的解决方案是使用微任务 async-await 技巧将我的一半代码放在滴答声的末尾。

let closed = false;
function* syncGenerator() {
  yield* ~20-trillion-calculated-results;
}
async function main() {
  try {
    for ( const value of syncGenerator() ) {
      syncWork(value);
      await new Promise(r => setImmediate(r)); // the new nasty
      if (closed) {
        syncGracefulCleanup();
        break;
      }
    }
  } catch ( err ) {
    handleError(err);
  } finally {
    syncGracefulCleanup2();
  }
}
process.on('SIGINT', () => closed = true);

Now, this works as I expected and the await allows the loop to be paused and allow SIGINT/SIGTERM to be processed and then picks up if closed is set to true.现在,这按我的预期工作,等待允许循环暂停并允许处理 SIGINT/SIGTERM,然后在关闭设置为 true 时接收。 YAY.. But DAMN it looks nasty. YAY .. 但该死的它看起来很糟糕。 I was hoping someone might have a better looking solution than this?我希望有人可能有比这更好看的解决方案?

You will need to keep the flag, but you can make your main logic simpler.您将需要保留标志,但您可以使主要逻辑更简单。 Consider考虑

let closed = false;
function* syncGenerator() {
  yield* ~20-trillion-calculated-results;
}

function main( generator = syncGenerator() ) 
{
    if (closed) 
    {
      syncGracefulCleanup();
    }
    else 
    {
        // assuming syncWork returns false when 
        // there are no more value
        if ( syncWork( generator.next() ) )
        {
            // next-ish off to the event loop. this is NOT recursive, 
            // even though it may look a bit like it
            setTimeout( () => main(generator), 0 );         
        }
    }
}

process.on('SIGINT', () => close = true);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM