仓颉编程语言的并发编程:线程模型与使用实践

并发编程已成为现代软件开发不可或缺的核心能力。随着多核处理器的普及和分布式系统的广泛应用,如何高效利用计算资源、提升程序性能成为开发者必须面对的问题。仓颉编程语言提供了强大而友好的并发编程机制,让开发者能够轻松构建高性能的并发应用。

文章目录

仓颉线程模型解析

仓颉中的线程是用户态的轻量级线程,并且支持抢占。

用户态:线程的创建、调度和管理都在用户空间完成,不需要操作系统内核的介入,这样可以降低上下文切换的成本,提升系统性能。

轻量级:比传统的操作系统内核线程更加轻巧,占用资源小,因此可以实现在应用程序中创建大量的线程,实现更细力度的并发控制。

抢占式调度:线程调度器可以在任何时刻中断线程的执行,将CPU资源分配给其他线程,这样可以防止某个线程长期占用CPU导致其他线程饥饿。

仓颉语言采用抢占式的线程模型作为其并发编程机制,并创新性地将线程概念分为两个层次:

  1. 语言线程(仓颉线程):这是开发者直接使用的编程接口,是语言层面的抽象。仓颉线程设计为轻量级的执行单元,开发者无需关心底层实现细节。

  2. 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:检查取消请求

实践建议与注意事项

  1. 避免阻塞native线程:在调用可能阻塞的foreign函数(如IO操作)时要特别小心,因为这会导致承载的native线程被阻塞,影响调度效率。

  2. 合理使用Future:根据场景选择适当的等待策略,避免不必要的阻塞。

  3. 线程安全:共享数据访问需要同步机制,仓颉提供了多种同步原语(未在本文展示)。

  4. 性能考量:虽然仓颉线程轻量,但也不应过度创建,需根据实际硬件资源合理设计。

终止线程

可以通过 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://cangjie-lang.cn/docs?url=%2F1.0.3%2Fuser_manual%2Fsource_zh_cn%2Fconcurrency%2Fconcurrency_overview.html

https://blog.csdn.net/Cool_foolisher/article/details/148251524

相关推荐
2501_919749035 小时前
配置flutter鸿蒙的环境和创建并运行第一个flutter鸿蒙项目【精心制作】
flutter·华为·harmonyos
Fanmeang7 小时前
华为交换机VLAN技术详解:从基础到高级应用
运维·网络·华为·vlan·交换机·mux vlan
Fanmeang7 小时前
华为路由器核心技术详解:数据包的智能导航系统
运维·网络·华为·路由器·路由表·路由协议
L.EscaRC8 小时前
仓颉(Cangjie)语言之网络编程浅析
网络·仓颉
赵得C11 小时前
智能体的范式革命:华为全栈技术链驱动下一代AI Agent
人工智能·华为·ai·ai编程
Fanmeang13 小时前
华为防火墙基础功能详解:构建网络安全的基石
运维·网络·安全·华为·防火墙·策略·安全域
爱笑的眼睛1114 小时前
深入解析ArkTS类型系统:构建安全高效的HarmonyOS应用
华为·harmonyos
猫林老师17 小时前
Flutter for HarmonyOS开发指南(四):国际化与本地化深度实践
flutter·华为·harmonyos
猫林老师1 天前
Flutter for HarmonyOS 开发指南(一):环境搭建与项目创建
flutter·华为·harmonyos