我正在使用Nashorn在Kotlin项目中运行一些JS脚本。一些脚本大量使用线程,并且由于其中一些线程的长期运行特性,因此希望使用协程代替,以便在需要重新加载脚本时可以取消协程(这种情况经常发生)。但是,我遇到的麻烦比我想象的要多。
以下是使用Java Thread
类的目标JS代码:
new Thread(function() {
Thread.sleep(2000);
print('hello');
}).start();
为了使用协程,我做了一个简单的ThreadWrapper:
class ThreadWrapper(private val method: Any) {
val thread = GlobalScope.launch {
newThread(this@ThreadWrapper)
suspendCoroutine<Unit> { cont ->
// call method, which is a nashorn scriptobjectmirror, and pass in cont
// as the first argument
JSLoader.callActualMethod(method, cont)
}
}
fun cancel() {
thread.cancel(CancellationException("Stopped by ThreadWrapper"))
}
companion object {
@JvmStatic
suspend fun sleep(timeMillis: Long) {
suspendCoroutine<Unit> { cont ->
Timer("Suspend Timer", false).schedule(timeMillis) {
cont.resume(Unit)
}
}
}
private val threads: MutableList<Job> = mutableListOf()
internal fun newThread(tw: ThreadWrapper) {
val job = tw.thread
threads.add(job)
}
internal fun cancelAll() {
threads.forEach {
it.cancel(CancellationException("Stopped by ThreadWrapper"))
}
threads.clear()
}
}
}
现在,我将这样编写JS代码:
new ThreadWrapper(function(continuation) {
Thread.sleep(2000, continuation);
print('Hello from module1!');
});
不幸的是,这不起作用。我确实看到了打印语句,但是它立即发生,忽略了睡眠调用。我对暂停函数的理解是,它们只是将延续作为第二个参数,仅此而已。我要将延续性传递给javascript函数,因此我应该能够使用该延续性调用暂停的函数,不是吗?
起初我以为是因为我从未真正在suspendCoroutine
调用中恢复协程。如果将callActualMethod
行移到suspendCoroutine
块的外部,并在块调用cont.resume(Unit)
的内部,则会得到一个IllegalStateException,指出协程已经恢复,这并没有多大用处也有感觉。
我也读过关于continuation interceptors的内容,但是这些内容似乎相当先进。我不确定为什么在我的方法中需要这些。
任何帮助将不胜感激,谢谢!