跳到主要内容
版本:release

关键特性汇总介绍


对象

  • 任意gs写的代码,必然在某个对象上
  • 命令行输入,每行命令都会编译1个对象

组件

  • 不论被component多少次,一个对象中永远只有1份
  • 总是先构造被component的代码,析构反之
  • 避免相互component,若有,由最外层代码书写顺序决定构造析构顺序

变量

  • 只有两种类型:成员变量,局部变量。
  • 没有静态变量、全局变量。
  • 共享变量:share_value,存取的时候都会拷贝,但能并发读写

只读

  • readonly 只读 parallel 并行 语义几乎相同
  • 对象声明为parallel
    • 所有变量都必须是只读的,声明时候必须写上 readonly
    • 所有方法都必须是并行的,无需显示声明为 parallel
  • 变量声明为readonly
    • 并非不能写,只是不能改变局部
    • 只能用 := 整体赋值,自行保证覆盖安全
    • 传递时不会拷贝,传递的内容无法修改
    • 区别于const成员变量
  • 变量声明为parallel
    • 可以并发修改容器内已存在的元素
    • 不可以新增/删除一有元素
    • 可以用 := 整体赋值,自行保证覆盖安全
    • 传递时不会拷贝,传递的内容无法修改
    • 可以看成预创建了一组readonly的变量放在一个不可改变大小的容器中
  • 方法声明为readonly
    • 只能访问只读变量
    • 被调用时候不切换域
    • 因而可以并行执行

协程

  • 初学可以理解为线程,但更为轻量
  • GS任意代码要执行,必然在某个协程中
  • 非抢占式,阻塞时挂起
  • 多对多模型

  • 就是区域范围的意思,亦可视作一把大锁,用于在并发场景下,保护所辖范围内的数据
    • 等价于其他语言中,用mutex管理一堆变量,只是做成了语言机制,方便编码,这是GS的特色
    • GS的任意变量(对象句柄也是变量)都必然隶属于某个域,局部变量亦不能例外
    • GS的任意变量,不能在其所属域外使用,跨域必然产生拷贝。只读变量例外,因为不能修改,拷贝和引用无差别。
    • 管道传输,函数变量参数,导致的数据传递,必须明确是否转移到了其他域
      • function.append_dup_arg, append_dup_arg_arr
      • queue.send_dup
  • 协程可以锁定域
    • 协程要执行代码,必然在某个域中
    • 当协程执行非并行方法时(跨域调用),会进入(自动锁定)该方法所在的域,并离开(自动释放)协程此前所在的域
    • 执行并行方法,不会产生跨域操作,但可以显式指定在哪个域内执行(仍旧不会产生跨域行为)
    • 协程将域锁定后,辖区内所有变量方法都只允许当前协程访问(并行方法例外)
    • 协程被阻塞时,会离开当前域,恢复时重新锁定
  • 跨域调用
    • 需使用=>,或者function.call_in_domain方法指定域
    • 所有参数会拷贝,返回值会拷贝,见上
    • 即使实际没有切域,拷贝仍然会发生
    • 除了拷贝开销,还有锁冲突开销
  • 显式锁定对象句柄,实际锁定了其所在的域

闭包

  • 实际声明了1个function变量,指向所定义的匿名函数
  • 可以捕获上下文变量,作为该匿名函数的隐含参数
  • 值变量捕获为拷贝,引用变量捕获为引用
  • 成员变量不捕获,因为该匿名函数就是所在对象上的成员方法

defer

  • 实际声明了1个闭包,但默认捕获为引用
  • 该闭包在离开作用域时调用,注意是闭包变量的作用域
  • 即使下文发生报错也会调用,这是主要利用的点
  • 防止该匿名函数再报错
  • 如有多个,调用顺序为声明顺序,不应依赖于此

#include 和 import

  • 所有符号都必须import后才对当前代码可见
  • 有时会使用include简化import的工作
  • include与C语言同样采用传统的宏处理机
  • include特性尽量少用,以后可能会废弃
  • 可以使用#pragma export_imports来导出这个文件下所有import的符号代替include
  • 参考M71的preimport.gs

#define

  • 支持通过#define声明宏定义
  • 可以使用#pragma export_macros来导出这个文件下所有#define的符号

热更新

  • monkey.patch 可以理解为重新编译并把函数指针替换
  • update可以理解为销毁对象 -> 重新编译 -> 创建对象