zoukankan      html  css  js  c++  java
  • 开源项目 D++

    D++  是 我 (K歌之王) 设计 的 一个 计算机编程 语言  。

     

    D++ 的 共同设计人 :   馥岚过野  ,   :|   ,    左边   ,    这是 3 个 网友 的 网名 。   他们 提供了 丰富 的 意见 和 经验,  涉及 软件 , 硬件 , CPU 架构 , 现有的 语言 和 GC , 程序架构 和 模型  ,  业界新闻  ……     我们展开了 热烈 和 卓有成效 的 讨论,    我从 他们 那里 获取了 许多 灵感  。

     

    D++   是   ILBC  的 一个 子项目,  有关 ILBC ,见 《ILBC 白皮书》  https://www.cnblogs.com/KSongKing/p/11070978.html   。

     

    D++   是 一个 通用 的 计算机语言,  可以用于 底层编程,也可以用于 业务编程 。   从名字上可以看出来,  既然 叫 D++ , 当然 希望 能够 做 C++ 做的 一些 事情 ,  因此, D++ 也偏 底层编程 一些 ,    用 D++ 写程序会 考虑 程序 本身 的 “技术性” 多一点, 而 业务编程 的 话,  希望 最好 不要 程序员 考虑 程序 本身 的  “技术性”  。

     

    了解 D++ ,可以加入 QQ 群   K 开源联盟  ,   群号  1004739167  。

     

    其实 一开始 搞 的 是 D# ,   后来发现 把 底层编程 和 业务编程  两个 需求 合在一个 语言 里 会让 语言 膨胀 变得 庞大, 于是 就 分开,  底层编程 是 D++ , 业务编程 可以用 类似 javascript 的 “高性能脚本语言” ,  可以比 javascript 简化 。也可以 搞 功能全面 的 D#  。

     

    高性能脚本语言 和 D# 都以 D++ 作为 中间语言 来 实现 。

     

    D++ 和 D# 的 语法 和 C# 差不多,就不多说了 。

     

    D++  有 类 、继承 ,  没有 虚函数多态  。    D#  有 虚函数多态,比如 虚方法 接口 抽象方法 抽象类 等 ,  还可以有  Lambda 表达式  等 。

     

    用  D++ 作为 中间语言 的 话,   怎么 来 实现 D# 的 虚函数多态 呢 ?     在 C++ 和 C# 里, 引用 是 一个 结构体,  如果 是用 D++ 作为 中间语言 的 话,  可以 让 D# 的 引用 是 D++ 里 的 一个 池对象,   池 就是 内存池 Pool  。

     

    D++   由  Heap , Pool , Bag  3 个 部分 组成 。

     

    Heap 是 CPU 多核共享的,  Heap 里 的 对象 称为 堆对象 。   严格的说,  Heap 是 多核共享 是指 多核 可以到 一个 堆 里 申请 空间,   且 一个 核 运行 的 程序 申请 的 空间 可以 在 别的 核 运行 的 程序 里 归还 堆  。

    至于 空间 里 的 数据 是否 多核共享,这个 不一定,  如果要 多核共享,  需要 使用 比如 原子类型  。

    也可以 搞  一核一堆 ,   但在  核 0 的 堆 里 申请 的 空间,  可以在 其它 核 比如 核 1 运行 的 程序 里  归还 堆,  这个 堆 当然 是 核 0 的 堆,    这也是 多核共享 Heap  。

     

    Heap 分为 const 区 和 Grid 区 ,   const 区 只分配不回收,  const 区 里 的 对象/数据 创建以后 只要 应用程序 不结束 会 一直存在 。 

    Grid 区 也称为 Grid Heap  ,

     

    Grid Heap 的 思想 也可以称为  “碎片隔离”  。   图中 的 “一格” 是 1 MB , 也就是 1 个 Grid 是 1 MB ,   也就是 Grid Size 是 1 MB  。

     

    可以把 Grid Size  分为 几种 不同 大小 的 规格,比如   8 KB  ,  128 KB  ,  1 MB  。

     

    如果  Heap 从 操作系统 取得的 “大块空间”(div) 是 1 MB ,   可以分配 128 个 8 KB Grid,   8 个 128 KB Grid  。

     

    Pool 是 内存池,  是 单核的,  同一时间 只能 运行在 一个 线程 上,  在 不同的时间,  Pool 可能 运行在 不同的 线程,但这些 线程 都是 同一个 核 的,  因为 Pool 里 的 数据 是 普通类型, 不是 原子类型,   不支持 严格的 多核同步数据  。

     

    要 多核同步数据,   也就是 多核共享数据,  要用 堆对象,  并且 在 堆对象 里 使用 原子类型  。

     

    Pool 使用时 要 lock 和 绑定 到 线程,  使用完 时 unlock 和 解除 绑定,    绑定 到 线程 可以 指定一个 寄存器 存放 池对象分配指针,  这样 可以 一个 时钟周期 new 一个 池对象  。

     

    一个 Request 对应 一个 Pool ,   Request 就是 执行一段代码,  让 程序 做 一些 工作  。  也可以说 Request 是 D++ 里 的 程序 的 基本单位  。  但还有 比 Request 更小 的 单位,是 任务(Task) 。

     

    如果 没有 IO 异步 ,   一个 Request 就是 一个 Task,    如果 有  IO 异步,    比如 有 一次 IO 异步 ,  一个 Request 会被 分解 为 2 个 Task  ,   一个 Task 是 执行 IO 异步 前 的 代码,  第二个 Task 是 执行 IO 异步 的 回调 。    如果 有 多次  IO 异步,  一个 Request 会被 分解 为  多个 Task  。

    这些 Task 是 串行 的,   串行 的 使用 Pool ,   所以也叫做  串行任务,串行 Task  。

    所以,  上面说,   Pool 使用时 要 lock ,  就是为了 确保  IO 异步 完成时,  回调 Task 们 串行 的 执行,   也就是 串行 的 使用 Pool ,   而不是 并发 的 执行,并发 的 使用 Pool  。

     

    Bag  就是 把 一些 数据 / 对象 封装在 一个 对象 里,  对外 提供一些 操作 这些 数据 / 对象 的 方法 ,    这个 对象 称为 Bag  。  其实 Bag 只是一个 习惯 的 称呼,  并不是 语法  。

     

    比如,   可以把  一些 对象图 或者 数据 封装为 一个 Bag,  比如 二叉树 ,  数据库 的 表  。

     

    Bag  和 外界 通过 值传递 传递数据,   也就是说,  Bag 的 方法 的 参数 和 返回值 都是 值类型, 比如 int, float, double ……  值类型数组 ,  结构体  。

     

    为了 提高效率,  不需要 每次 读写 Bag 里 的 数据 都要 把 数据 复制出来 又 复制进去,   Bag 可以返回一个 类似 C# 里的 Span<T> 的 东西,这个 东西 实际上 是一个 结构体,在 D++ 里 称为  Local Agent ,   在 语法 上,  需要 Bag 是  readonly 变量, 才能 返回 Local Agent,   D++  也可能 需要 提供一些 语法支持 让 Local Agent 有一个 作用域,以及 使用完(作用域结束)时 可以调用 一个 类似 Dispose() 的 方法 。

     

    Bag 是 堆对象,   是 堆对象 的 一种,   上面也说了,  Bag 只是一个 习惯性 的 称谓,  并不是 严格 的 定义,也不是 语法  。

     

    所有 的 堆对象 都是 native class ,   native class 就是用 InnerC 编写 的 class ,   D++ 没有 编写 堆对象 的 语法 。

     

    D++ 提供了 编写 native class 的 语法,   类似一个 接口 定义,   定义出 native class 的 成员(方法),  包括 这些 成员(方法) 的 签名  。

     

    D++  编译器 会 把 接口定义 翻译成 InnerC 的 表达,   程序员 去 编写 具体 的 InnerC 的 代码实现,  InnerC 编译器 会 把 接口 和 实现 的 InnerC 代码 放到一起 编译 ,  若 接口 和 实现 不对应,  会 报错  。

     

    这 本身也是 和 Native Code 交互 的 规范 和 技术 。

     

    可以 来 看 一段   D++ 代码 :

                 

                  

                 

     

     

    等待接收 Windows 消息 也可以 算作一次 IO  ,     如此,  刚刚 的 编程模式 也可以用于  窗体程序 的  Windows 消息循环 。

     

    事实上,  用 刚刚 的 编程模式,   Windows 消息循环 和 多个 IO 可以 并发/并行 的 进行,(对 Pool 来说 是 并发,对这些 IO 自身来说 是 并行 )

     

    可以 为 每一个 IO(Windows 消息)执行 回调,也可以 等待 一组 IO(Windows 消息) 都 完成(收到) 时 执行 回调,  后者 类似 Promise ,也可以说 就是 Promise 。

     

    前者 和 后者 可以混合,  既 可以 为 一些 IO 单独 执行 回调,也可以 把 单独执行回调 的 IO 或 其它 的 IO 合成一组,等这些 IO 全部完成时 执行 回调 。

     

     

    Pool 和  Bag  一开始的时候可以从 Grid Heap 申请一个 小 的 Grid , 比如 8 KB ,

     

    new 子对象从 Grid 中 顺序 分配空间 , 

     

    当 new 的 子对象 的 Size 大于 Grid 的 剩余空间 时, 

     

    如果 子对象 Size 大于 Grid 空间 的 1/10 , 则 从 Grid Heap 申请一个 更大一级 的 Grid ,比如 128 KB,

     

    如果 子对象 Size 小于 Grid 空间 的 1/10 ,  则 从 Grid Heap 申请 一个 同级 的 Grid, 8 KB 。

     

    如果 Bag 当前 所有 的 Grid 的 空间总和(Grid 的 固有空间总和,不是 已使用空间总和 也不是 剩余空间 总和)达到了 当前 Grid 中 最高级(最大) 的 Grid 的 更高一级 Grid 的 Size,那么接下来 再申请 Grid, 则 申请 这个 更高一级 的 Grid 。

     

    比如, 当前 Bag 的 Grid 中有 8 KB 的, 有 128 KB 的,最高级(最大)的 是 128 KB ,  且 这些 Grid 加起来 已经 达到了 1 MB 以上,则 下次 申请 Grid 就  申请 1MB 的 Grid 。

     

    池对象 的 Size 只要 小于 最高级别 (最大)的 Grid 的 1/10 就行了 。

     

    其实 最大 的 Grid 也可以 比 1 MB 大,比如   10 MB , 100 MB  ,

     

    根据 上面的规则, 若 当前 Bag 内 所有 Grid 空间 总和 是 101 MB, 则再申请 Grid 就是 100 MB, 于是 Bag 内 Grid 总空间 达到 201 MB 。

     

    程序员 可以 通过 Pool / Bag 的 构造函数 参数 指定 默认 Grid Size(级别),这样  Bag  一开始就按照 指定 的 Grid Size 申请 Grid 。

     

    比如 有 的 Bag 要存的数据比较多, 就可以指定 Grid Size 为 128 KB 或 1MB,

     

    这样可以减少 初始 的 一段时间内 从 Grid Heap 申请 Grid 的 次数 。

     

    上文说了,  Heap 是 多核共享,  因此 管理 Heap 的 数据 是 原子类型,  每次 分配 和 回收 空间 要 CAS Lock 和 修改 Heap 管理数据,  CAS Lock 也是 原子操作,   也就是说, 每次 从 Heap 里 分配 和 回收 空间 需要 若干次 原子操作,   从 Grid Heap 里 分配 和 回收空间 也许需要 100 个 时钟周期 ,  时间花费 是 比较多的 ,是 比较重型 的 操作 。

     

    减少 从 堆(Heap)里 申请空间(申请 Grid )的 次数 可以 提高性能 。

     

     

    堆对象 可以返回 堆对象,  当 堆对象 返回到 D++  层面时,  按 引用计数 管理回收,

     

    这就要求, D++ 层面 的 堆对象, 应是 树形结构,      简单的说,就是 没有 循环引用 。

     

    先说这些,  具体 的 内容 还有一些,   暂时 懒得写了  。

     

  • 相关阅读:
    Hibernate查询基本语句 全新时代
    word表格设置背景色方法 全新时代
    Html网页背景渐变色代码 全新时代
    FlashFXP列表参数错误解决方法 全新时代
    svn导出功能不包含.svn文件 全新时代
    JDBC连接SQL Server测试代码及异常 全新时代
    javascript:滚动新闻
    C# 时间函数(几个常用时间,程序运行计时,页面运行计时)
    C#:当把U盘放插入,然后程序自动将U盘的内容复制到本地硬盘
    C#:转换成中文数字
  • 原文地址:https://www.cnblogs.com/KSongKing/p/14800180.html
Copyright © 2011-2022 走看看