异步系统
Alia 支持原生并行处理、线程控制与异步编程。核心概念包括 run/await(线程启停)、Channel(线程间通信)和 select(多路选择)。
语法总览
run <Stack body> ~ 在独立线程中执行栈,返回附带线程状态的 Stack
run <Variable stackVar> ~ 启动已有的 Stack 对象
await <Stack stackVal> ~ 等待并行栈完成,返回执行结果;非并行栈报 Stack is not running in parallel
new Channel[<Number cap>] ~ 创建有缓冲信道
new Channel[] ~ 创建无缓冲信道
<Channel>.send <Value> ~ 发送值;已关闭或有缓冲已满时抛错
<Channel>.trySend <Value> ~ 非阻塞发送,返回 Boolean
<Channel>.receive ~ 接收值;有缓冲为空时返回 Null,无缓冲为空时阻塞
<Channel>.tryReceive ~ 非阻塞接收,空时返回 Null
<Channel>.close ~ 关闭信道
select <Stack body> ~ 多路选择,body 中仅允许 case receive / case send 子句
case receive <Variable> from <Value> <Stack body> ~ 接收分支
case send <Value> to <Value> <Stack body> ~ 发送分支
零参数信道与栈方法采用 call 形式:call ch.receive、call ch.tryReceive、call ch.close、call t.join、call t.result、call t.detach、call s.run。属性采用直接访问形式:ch.capacity、ch.length、ch.isClosed、t.isRunning、t.isDone、t.isDetached。
Channel 信道
Channel 是 Alia 内置的线程安全通信信道,对标 Go 语言的 channel。
创建信道
const ch = new Channel[5]
const uch = new Channel[]
assert ch.capacity == 5 error 'buffered capacity mismatch'
assert uch.capacity == 0 error 'unbuffered capacity mismatch'
基本操作
const ch = new Channel[3]
ch.send 'hello'
ch.send 42
assert ch.length == 2 error 'length mismatch after send'
assert (call ch.receive) == 'hello' error 'receive mismatch'
assert (call ch.receive) == 42 error 'receive number mismatch'
assert ch.length == 0 error 'length mismatch after receive'
非阻塞操作在缓冲未满或非空时成功,条件不满足时返回 false 或 Null,不抛错:
const ch = new Channel[1]
assert ch.trySend 'x' error 'trySend mismatch'
assert (ch.trySend 'y') == false error 'trySend full mismatch'
assert (call ch.tryReceive) == 'x' error 'tryReceive mismatch'
assert (typeOf call ch.tryReceive) == 'Null' error 'empty tryReceive mismatch'
关闭操作将信道标记为已关闭,已缓冲的值仍可接收,向已关闭信道发送时抛错:
const ch = new Channel[2]
ch.send 'a'
call ch.close
assert ch.isClosed error 'should be closed'
assert (call ch.receive) == 'a' error 'buffered receive after close mismatch'
有缓冲 send 在缓冲区已满时抛 Channel buffer is full,receive 在缓冲区为空时返回 Null。无缓冲 receive 在缓冲区为空且未关闭时阻塞等待,close 唤醒等待者。
属性
| 属性 | 类型 | 说明 |
|---|---|---|
capacity | Number | 缓冲区容量(无缓冲=0) |
length | Number | 当前缓冲区元素数 |
isClosed | Boolean | 是否已关闭 |
属性为直接访问形式,不经 call。
线程(run / await)
启动线程
run 将 Stack 放入独立线程并行执行,返回附带线程状态的同一 Stack 对象:
const t = run {
print 'Hello from thread!'
42
}
assert t.isRunning error 'thread should be running'
工作线程基于栈源码重建独 立运行时执行,不共享创建线程的变量与信道缓冲。需要传递结果的场景由 await 或 call t.join 在主线程收集。
等待线程
await 阻塞当前线程,等待目标线程完成并返回执行结果:
const t = run { 42 }
const v = await t
assert v == 42 error 'await result mismatch'
assert t.isDone error 'should be done'
await 的目标须为处于并行执行中的 Stack。目标非并行栈时报 Stack is not running in parallel。重复启动已运行的栈报 Stack is already running in parallel。
const s = { 42 }
assert s.isRunning == false error 'fresh stack should not be running'
assert s.isDone == false error 'fresh stack should not be done'
线程属性
| 属性/方法 | 类型 | 说明 |
|---|---|---|
isRunning | Boolean | 是否正在并行执行,直接访问 |
isDone | Boolean | 是否已执行完毕,直接访问 |
isDetached | Boolean | 是否已分离,直接访问 |
join | → Value | 等待完成并返回结果(阻塞),调用形式为 call t.join |
detach | → Null | 分离线程,标记 isDetached 并返回 Null,调用形式为 call t.detach |
result | → Value? | 非阻塞获取结果,未完成返回 Null,调用形式为 call t.result |
const t = run { 40 + 2 }
assert (call t.join) == 42 error 'join result mismatch'
assert t.isDone error 'should be done after join'
const t = run { 42 }
call t.detach
assert t.isDetached error 'should be detached'
await t
select 多路选择
select 语句在多条信道操作中等待,执行第一个就绪的分支。分支就绪判定基于非阻塞 tryReceive/trySend:
const ch1 = new Channel[1]
const ch2 = new Channel[1]
ch1.send 'A'
ch2.send 'B'
let received = ''
select {
case receive v1 from ch1 {
received = v1
}
case receive v2 from ch2 {
received = v2
}
}
assert received == 'A' | received == 'B' error 'select receive mismatch'
当没有信道就绪时,select 不执行任何分支:
const ch = new Channel[1]
let ran = false
select {
case receive v from ch {
ran = true
}
}
assert ran == false error 'select empty mismatch'
发送分支在目标信道可写入时就绪:
const ch1 = new Channel[1]
const ch2 = new Channel[1]
ch1.send 'A'
let out = ''
select {
case receive v from ch1 {
out = v
}
case send 'B' to ch2 {
out = 'sent'
}
}
assert out == 'A' error 'select send branch mismatch'
完整示例:Worker Pool
并行计算在独立线程中执行,信道在主线程中完成任务分发与结果收集。run 体不捕获外部信道,跨线程结果经 await 回到主线程后再入信道:
const t1 = run { 1 + 2 }
const t2 = run { 3 * 4 }
const v1 = await t1
const v2 = await t2
const results = new Channel[10]
results.send v1
results.send v2
call results.close
assert results.length == 2 error 'results length mismatch'
assert (call results.tryReceive) == 3 error 'first result mismatch'
assert (call results.tryReceive) == 12 error 'second result mismatch'
信道任务流水线在主线程中顺序执行:
const tasks = new Channel[10]
const orderedResults = new Channel[10]
each i in [1, 2, 3, 4, 5] {
tasks.send i
}
call tasks.close
while tasks.length > 0 {
const item = call tasks.tryReceive
if typeOf item == 'Number' {
const doubled = item * 2
orderedResults.send doubled
}
}
call orderedResults.close
assert orderedResults.length == 5 error 'ordered results mismatch'
标准库异步函数
部分标准库函数返回符合 Alia 异步模型的 Stack(isRunning/isDone/isDetached 属性与 join/result/detach 方法,经 call 调用),经 await 消费:
io.read/io.readChar/io.readKey:属性式访问返回 Stack,call task.join惰性执行同步读取,EOF 返回Nullio.readLine/io.readPassword:单参数调用返回 Stack,io.readLine 'prompt'传入提示词,EOF 返回Nullweb.httpRequest:单参数对象调用,请求在后台线程执行,await后经task.response访问响应对象,await表达式可一步取得响应
await 接受返回 Stack 的表达式,一步取得结果;栈字面量、并行栈与上述异步 Stack 的 typeOf 均为 'Stack'。web.httpRequest 的 await 语义与测试一致:const task = web.httpRequest opts 后 await task 经 task.response 访问响应对象,await web.httpRequest opts 一步取得响应;以下示例仅创建任务并校验 Stack 形态,不发起等待,避免示例依赖外部服务:
import 'web' as web
const opts = *[url: 'http://localhost:19995/get']
const task = web.httpRequest opts
assert task.isRunning error 'http task should be running'
assert (typeOf task) == 'Stack' error 'http task type mismatch'
import 'web' as web
const parsed = web.urlParse 'https://localhost/path'
assert parsed.protocol == 'https' error 'protocol mismatch'
assert parsed.hostname == 'localhost' error 'hostname mismatch'
import 'web' as web
const server = call web.serverCreate
server.close
assert true error 'server close mismatch'
web.serverCreate 经 call 创建服务对象,server.close 为属性式访问,访问时同步执行关闭并返回已完成的 Stack。server.listen 与 addRoute 为普通服务方法。