鹦鹉虚拟机/多线程和并发
多线程是解释型语言(如 Perl 5)在过去遇到一些问题的领域。以 Perl 5 为例,它有一个非常有漏洞且不可靠的线程实现,它不可扩展。
与 Perl 5 相比,Perl 6 在核心语言中包含了高级多线程和并发功能。为了支持 Perl 6 语言的所有这些高级功能,鹦鹉也必须提供相同的功能。
虽然不是技术上的“多线程”,但协程代表了一种简单的并发形式,随着它被主流程序员接受,将找到许多有趣的用途。协程就像子例程,它们使用yield语句而不是return语句。.yield
语句导致协程向调用者返回一个值。但是,.yield
不会导致协程退出、消失或丢失其当前状态。下次调用者调用协程时,协程将从上次停止的地方继续执行。以下是一个例子
.sub 'MyCoroutine' .yield(1) .yield(2) .return(3) .end
.sub 'MyCaller' $I0 = 'MyCoroutine'() say($I0) $I0 = 'MyCoroutine'() say($I0) $I0 = 'MyCoroutine'() say($I0) .return
函数MyCaller
的输出将是
1 2 3
协程在需要维护持久状态的地方立即有用,但在多个调用者或多个线程之间协调该状态可能很困难。一个这样的例子是在文件或数据库访问中,协程可以序列化访问并维护有关文件大小和文件某些特征位置的持久状态信息。
协程在其他地方也称为“延续”,甚至在其他地方称为“延续三明治”。
协程的参数只在第一次调用协程时传递,或者在执行.return
语句后任何时候调用协程时传递。以下是一个例子
.sub 'MyCoroutine' .param int a .yield(a) .yield(a) .yield(a) .return(a) .end .sub 'main' :main $I0 = 'MyCoroutine'(1) # the "call" say $I0 $I0 = 'MyCoroutine'(2) # "continuation" say $I0 $I0 = 'MyCoroutine'(3) # "continuation" say $I0 $I0 = 'MyCoroutine'(4) # "continuation" say $I0 .end
这段代码将打印以下结果,即使MyCoroutine
函数的参数在每次调用时都会改变
1 1 1 1
这是因为只有第一次调用MyCoroutine
实际上是创建局部参数的函数调用。其他对MyCoroutine
的调用只是延续,而不是调用。延续不会创建新的参数变量。
协程中的 return 调用会导致它向调用者返回一个值并像往常一样销毁其当前词法范围。但是,yield 调用将返回一个值而不会销毁当前词法范围。然后生成将允许协程保持其当前状态并下次调用时恢复其执行。
这就是协程系统核心的所在,协程 PMC。协程 PMC 是一个对象,它存储协程的状态,以便可以连续多次调用它。延续 PMC(协程的超类)是存储的解释器状态。协程通过在调用.yield
指令时存储一个延续,并在下次调用协程时调用该延续来操作。
鹦鹉中的线程目前尚未实现,尽管开发人员正在积极努力。本节中的材料主要是基于鹦鹉设计文档的推测。一旦并发正式实现,所有这些信息都将更新。 |
在内部,鹦鹉支持多种不同的方法来执行线程。幸运的是,所有这些不同的方法都是抽象的,细节对 HLL 程序员是隐藏的。鹦鹉的并发系统是模块化的,因此可以在以后将新的多线程技术添加到鹦鹉中,HLL 程序员将能够从这些更改和添加中受益,而无需对他们的代码进行任何更改。
有四种基本操作可用于创建和管理新线程。在鹦鹉中,线程都抽象在任务PMC 中。要创建一个新线程,首先创建一个新的任务 PMC,然后将其添加到调度程序中。