在Lu脚本中使用协程
欢迎访问:http://www.forcal.net/
最近,在Lu脚本中增加了协程支持。
如果Lu表达式(函数)中使用了函数yield,该表达式称为一个协程(coroutine)。协程不能递归运行,只有这一个限制。Lu协程有4种状态:正常、运行、挂起、 终止。正常态是可以运行但还没有运行的状态;终止态协程是不能运行的,如果运行将返回nil。与协程相关函数有5个:
yield:挂起协程并立即返回表达式(函数)的值。
status:查询表达式(包含协程)的状态。
abort:中止挂起的协程,此时协程处于正常态。
terminate:终止协程,协程处于终止态,不能运行。
resume:重启一个终止的协程,协程转为正常态。
详细说明:
28.29 查询表达式(包含协程)状态 status(p):
p是一个表达式句柄。正常返回一个整数表示表达式状态:0:普通表达式;1:普通表达式正在运行;2:普通表达式递归运行;5:协程;6:协程正在运行;7:协程挂起;8:协程终止。p非法时返回nil。
28.30 中止挂起的协程 abort(p):
p是一个协程句柄,正处于挂起状态。协程中止后,可以再次从头开始执行。操作成功返回true,否则返回false。
28.31 终止协程 terminate(p):
p是一个协程句柄,处于正常等待运行状态或者挂起状态。协程终止后将不能执行,执行时总返回nil。操作成功返回true,否则返回false。
28.32 重启一个终止的协程 resume(p):
p是一个协程句柄,正处于终止状态,重启后可以运行。操作成功返回true,否则返回false。
例子1:
f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888;
f[0]; f[0]; f[0]; f[0]; f[0]; f[0]; f[0]; f[0];
结果(返回888时协程转为了正常态):
1
2
3
4
5
888
1
2
例子2:协程状态转换
f(x:i)= i=0, while{(i++, i<=5), yield(i)}, 888;
f[0]; f[0]; status[@f]; f[0]; abort[@f]; f[0]; terminate[@f]; status[@f]; f[0]; resume[@f]; f[0]; f[0]; f[0];
结果(对照status、abort、terminate、resume等函数的返回值很容易理解以下结果):
1
2
7
3
true
1
true
8
nil
true
1
2
3
例子3:生产者与消费者
!!!using["sys"];
生产者(x:pp,k,i:p)= //自变量x仅用于避免该函数自动执行
p=nil, //p是模块变量,用于传递数据
pp=lu[2,"aaa",6], //pp存放数据
k=len(pp), i=0,
while{i<k,
o["\r\n---生产者---\r\n"], //打印所在位置
if{isnil(p), p=pp[i++], o["\r\n---生产者发送数据 ", p, "\r\n"]}, //p=nil时发送一个数据
yield(true) //挂起协程
};
消费者(x:i:p)= //自变量x仅用于避免该函数自动执行
i=0, //控制变量,i为偶数时消费者才消费
while{true,
o["\r\n---消费者---\r\n"], //打印所在位置
if[++i%2, yield(true)], //i为奇数时挂起协程
if{!isnil(p), o["\r\n---消费者输出数据 ", p, "\r\n"], p=nil}, //p!=nil时输出一个数据
if[status(@生产者)==8, break()], //如果生产者终止,消费者就退出
yield(true) //挂起协程
};
main()=
while{true,
o["\r\n---main---\r\n"], //打印所在位置
生产者[0],
if[status(@生产者)==5, terminate(@生产者)], //如果生产者结束,就终止生产者
消费者[0],
if[status(@消费者)==5, break()] //如果消费者结束,就退出
};
结果:
---main---
---生产者---
---生产者发送数据 2
---消费者---
---main---
---生产者---
---消费者输出数据 2
---main---
---生产者---
---生产者发送数据 aaa
---消费者---
---消费者输出数据 aaa
---main---
---生产者---
---生产者发送数据 6
---消费者---
---main---
---消费者输出数据 6