并发编程已成为现代软件开发不可或缺的核心能力。随着多核处理器的普及和分布式系统的广泛应用,如何高效利用计算资源、提升程序性能成为开发者必须面对的问题。仓颉编程语言提供了强大而友好的并发编程机制,让开发者能够轻松构建高性能的并发应用。
文章目录
仓颉线程模型解析
仓颉中的线程是用户态的轻量级线程,并且支持抢占。
用户态:线程的创建、调度和管理都在用户空间完成,不需要操作系统内核的介入,这样可以降低上下文切换的成本,提升系统性能。
轻量级:比传统的操作系统内核线程更加轻巧,占用资源小,因此可以实现在应用程序中创建大量的线程,实现更细力度的并发控制。
抢占式调度:线程调度器可以在任何时刻中断线程的执行,将CPU资源分配给其他线程,这样可以防止某个线程长期占用CPU导致其他线程饥饿。
仓颉语言采用抢占式的线程模型作为其并发编程机制,并创新性地将线程概念分为两个层次:
-
语言线程(仓颉线程):这是开发者直接使用的编程接口,是语言层面的抽象。仓颉线程设计为轻量级的执行单元,开发者无需关心底层实现细节。
-
native线程 :这是实际执行语言线程的操作系统线程,作为语言线程的载体。仓颉采用M:N线程模型,即多个语言线程(M)运行在少量native线程(N)上,通过用户态调度实现高效并发。
这种设计带来了显著优势:
- 轻量级:仓颉线程创建和切换开销远小于操作系统线程
- 高吞吐:通过用户态调度避免了频繁的内核切换
- 易用性:开发者无需处理底层线程管理细节
仓颉线程的创建与使用
创建线程
在仓颉中创建线程非常简单,使用spawn关键字即可:
ts
main() {
spawn { =>
println("这是在新线程中执行的代码")
}
println("这是主线程")
}
spawn接受一个无形参的lambda表达式,其中的代码将在新线程中执行。需要注意的是,主线程结束时所有子线程也会被终止,无论是否完成执行。
简单的使用demo:
typescript
package Myprj
// 导包
import std.sync.*
import std.time.*
main () {
spawn {
// 阻塞子线程3秒
sleep(Duration.second * 3)
for(i in 0..3) {
println("我是子线程: ${i}")
}
}
for(i in 0..3) {
println("我是主线程: ${i}")
}
}
线程同步与结果获取
通过Future<T>可以等待线程完成并获取返回值:
ts
import std.sync.*
import std.time.*
main() {
let fut = spawn {
sleep(Duration.second)
return 42 // 返回计算结果
}
// 阻塞等待结果
let result = fut.get()
println("计算结果: ${result}")
}
Future<T>提供了多种控制方式:
get():阻塞等待线程完成get(timeout: Duration):带超时的等待tryGet():非阻塞尝试获取结果
线程属性访问
通过Thread类可以访问线程属性:
ts
main() {
let fut = spawn {
println("线程ID: ${Thread.currentThread.id}")
}
println("新线程ID: ${fut.thread.id}")
fut.get()
}
常用属性包括:
Thread.currentThread:获取当前线程id:线程唯一标识hasPendingCancellation:检查取消请求
实践建议与注意事项
-
避免阻塞native线程:在调用可能阻塞的foreign函数(如IO操作)时要特别小心,因为这会导致承载的native线程被阻塞,影响调度效率。
-
合理使用Future:根据场景选择适当的等待策略,避免不必要的阻塞。
-
线程安全:共享数据访问需要同步机制,仓颉提供了多种同步原语(未在本文展示)。
-
性能考量:虽然仓颉线程轻量,但也不应过度创建,需根据实际硬件资源合理设计。
终止线程
可以通过 Future 的 cancel() 方法向对应的线程发送终止请求,该方法不会停止线程执行。开发者需要使用 Thread 的 hasPendingCancellation 属性来检查线程是否存在终止请求。此外Thread类,通过它还可以查看线程的id、名称等信息。
Thread类无法直接通过构造函数得到对象,可以通过Thread类的静态成员属性currentThread获取当前线程Thread对象,或者通过Future对象的属性thread获取Future对象对应的线程Thread对象。
一般而言,如果线程存在终止请求,那么开发者可以实施相应的线程终止逻辑。因此,如何终止线程都交由开发者自行处理,如果开发者忽略终止请求,那么线程继续执行直到正常结束。
示例代码如下:
typescript
import std.sync.SyncCounter
main(): Unit {
let syncCounter = SyncCounter(1)
let fut = spawn {
syncCounter.waitUntilZero() // block until the syncCounter becomes zero
if (Thread.currentThread.hasPendingCancellation) { // Check cancellation request
println("cancelled")
return
}
println("hello")
}
fut.cancel() // Send cancellation request
syncCounter.dec()
fut.get() // Join thread
}
输出结果如下:
bash
cancelled
总结
仓颉编程语言的线程模型通过抽象分层和用户态调度,在保持易用性的同时提供了高性能的并发能力。开发者只需关注业务逻辑,无需陷入底层细节,即可构建高效的并发应用。随着仓颉语言的持续发展,其并发编程能力将进一步增强,为开发者解决更复杂的并发问题提供强大支持。
参考文档
https://blog.csdn.net/Cool_foolisher/article/details/148251524