如何杀死一个线程,停止 Raku 中的承诺执行

tin*_*ino 7 asynchronous raku

我正在寻找等待停止(发送异常)到SIGINT. 文档中给出的示例退出了整个过程,而不仅仅是一名工人。

有人知道如何“杀死”、“取消调度”、“停止”正在运行的线程吗?

这是针对p6-jupyter-kernel问题或这个REPL 问题

当前的解决方案是重新启动 repl 但不杀死被阻塞的线程

await Promise.anyof(
  start {
      ENTER $running = True;
      LEAVE $running = False;
      CATCH {
          say $_;
          reset;
      }
      $output :=
        self.repl-eval($code,:outer_ctx($!save_ctx),|%adverbs);
  },
  $ctrl-c
);
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 7

简短版本:不要为此使用线程,请使用进程。通常,在这种情况下,杀死正在运行的进程可能是最好的办法。

长答案:首先,澄清问题中的一些困惑是有帮助的。

首先,没有“跑步Promise”这样的东西;aPromise是用于传送异步操作结果的数据结构。一个start块实际上在做三件事:

  1. 创建一个Promise(它评估为)
  2. 安排一些代码运行
  3. 安排运行该代码的结果通过保留或破坏 Promise

这听起来可能有点学术,但确实很重要:aPromise不知道最终会保留或破坏它的内容。

其次,start块不是 - 至少在内置调度程序中 - 由线程支持,而是在线程池上运行。即使您能想出一种“取出”线程的方法,线程池调度程序也不会对它希望从工作队列中吃掉的线程之一消失感到满意。你可以写你自己的调度,每次确实回来工作,一个新的线程,但还不是一个完整的解决方案:如果什么一段代码的用户已经要求其自己的时间表工作的执行,然后awaits表示? 那么没有一个线程可以杀死来真正使事情停止。

然而,让我们假设,我们确实设法解决了所有这些问题,并且我们得到了一个我们真正想要在没有他们合作的情况下杀死的一个或多个线程的列表(合作情况相当容易;我们使用 aPromise并有代码轮询每隔一段时间,die如果取消Promise被保留/破坏)。

任何希望能够停止因任何事情(不仅是计算,还有 I/O、锁定等)阻塞的线程的机制都需要来自底层运行时(例如 MoarVM)的深度集成和合作。例如,尝试取消当前正在执行垃圾收集的线程将是一场灾难(很可能会导致整个 VM 死锁)。其他不幸的取消时间可能会导致内存损坏,如果它在不安全的操作中途中断,如果被杀死的线程持有锁,则在其他地方死锁,等等。因此,人们需要某种安全指向机制。(我们已经在 MoarVM 中按照这些思路知道什么时候对 GC 是安全的,但是取消意味着不同的需求。它可能横切了 VM 代码库的许多部分。)

这还不是全部:同样的情况也在 Raku 语言级别上演。Lock::Async例如,不是一种底层运行时知道的锁。可能最好的办法是尝试拆除调用堆栈并运行所有LEAVE移相器;这样就有了一些希望(如果人们使用该.protect方法;如果他们只是打电话lockunlock明确地说,我们已经完成了)。但即使我们设法不泄漏资源(已经是一个很大的问题),我们仍然不知道——总的来说——我们杀死的代码是否使世界处于任何一种一致的状态。在 REPL 上下文中,这可能会在访问相同全局状态的后续执行中导致可疑的结果。这可能很烦人,但真正让我害怕的是人们在生产系统中使用这种取消机制——如果我们实施它,他们就会这样做。

因此,有效地实现这样的功能需要在运行时和 Rakudo 本身上做大量困难的工作,结果将是一个巨大的脚步(我什至没有列举所有可能出错的事情,只是第一个想到的很少)。相比之下,杀死进程会清除所有资源,并且进程有自己的内存空间,因此也不存在一致性问题。


Eli*_*sen 5

如果一个线程不想被停止,目前没有办法停止它。

一个线程可以每隔一段时间检查一个标志,如果设置了该标志,就决定调用它退出。如果我们有办法在一个线程内从另一个线程抛出异常,那就太好了。但我们没有,至少据我所知没有。