我正在用 Rust 开发一个执行器来处理计算密集型任务,作为大型 Web 应用程序的一部分。执行器从 RabbitMQ(使用 lapin)接收作业并处理各种 CPU 密集型操作,其中包括一些内部使用 rayon 的操作。我知道异步会使人造丝的使用变得复杂。计算后或任务取消后,它将结果或取消状态传达回 RabbitMQ。
所涉及的操作超出了我的控制范围,主要由长时间运行的并行图算法组成。我正在探索通过单独的 RabbitMQ 取消队列反应性取消这些任务的策略,而无需重写底层库,因为它们(据我理解)与异步模式不兼容,并且出于安全原因普遍缺乏内置任务取消支持。
我使用 tokio 制作了一个执行器原型,只是在事后才认识到 rayon 的潜在问题。目前的取消策略是基于 tokio oneshot 通道,它会低效地丢弃任务,而不会释放 CPU 资源。我正在寻求有关如何制作一个惯用的执行器的建议,该执行器可以有效地取消任务并符合 Rust 的安全保证。
编辑:我会尝试更具体:本质上,我正在寻找一种策略来从另一个线程取消(长时间运行、阻塞、CPU 限制)任务,有效地中止计算并释放 CPU。使用 tokio 的 oneshot 通道等机制优雅地发出关闭信号不是一个选择,因为我无法控制长时间运行操作的实现。
停止线程的唯一合理方法是让它与之合作。 有多种方法可以做到这一点,但它们都涉及一些普遍的东西:
async
代码可能会故意让出(从Poll::Pending
返回poll()
),以便让执行者或包含未来的人有机会决定不再轮询它。panic!()
关于如何进行的一些想法:
如果您调用自身的代码使用 Rayon,那么也许您可以向 Rayon 提供取消功能(或运行修补版本),该功能将检查每个rayon::join
让 Java 弃用其
Thread.stop()
线程可以从其他线程的堆栈借用数据; Rayon 和
std::thread::scope()
这两件事都可以通过添加适当的检查或禁止它们来解决(例如,严格使用通道和原子,不使用锁),但您必须确保线程执行的所有代码