协程设计需要注意的两个小问题及解决
2017-10-30 03:03
387 查看
A 如何实现扩容
B 协程状态的保存与恢复
A 如何实现协程扩容
通知机制
扩容
B 协程状态保存与恢复
状态有哪些如何恢复
什么形式探测这些状态
这两天我尝试仿照Golang正在设计一款协程库。
协程有什么用途呢?合理利用资源。通用的进程和线程模型都耗费了不应该耗费的资源,要想处理更多并发得自己管理任务切换。
我实现的协程比较简单。在设计过程中发现了两个小难点,分享给大家。
Golang如何处理扩容的呢?
它不允许直接的指针操作,所以它可以通过移动内存和其上的数据达成目的。
C语言肯定是限制不了了。
如何获得用户即将超过栈的消息?
C语言编译会对 可能超过栈的操作 建立一个栈检查,防止其越过栅栏页,此外通过栅栏页来使我们能够侦测到超出栈但是不超出一个页面的行为。
我采用的是Windows系统提供的预订和调拨内存操作。详细内容可参考:《Windows核心编程第五版》
预订不占用内存,只是占号码范围,我们知道虚拟内容是假的。
所以方法是这样:
给每个协程单元预订足够的内容(比如,像线程的默认大小一样1M)。
实际**调拨**4kb。
这样还顺带解决栅栏页的问题,因为未被调拨的空间访问,返回AV异常。我们接到这个异常然后判断范围后就去尝试调拨。
举个例子:
协程A执行甲乙两个阻塞任务。
但乙操作预计属于可等待操作,可以让出时间片。
Windows的做法是:
怎么在R3实现这个操作呢?
通过触发异常我们可以获取完整的信息,但是这个操作太费时间,所以我设计了一段汇编来完成我们的任务:
我们只需要保存:
OK。
下面是详细流程:
预订地址空间区域,给区域调拨来自页交换文件的物理存储器。
根据自己的需要来设置页面的保护属性。
非常快速,但是要考虑如何安排数据
内联异常
这是一种非常好的方式。但是涉及异常,影响速度?
B 协程状态的保存与恢复
A 如何实现协程扩容
通知机制
扩容
B 协程状态保存与恢复
状态有哪些如何恢复
什么形式探测这些状态
这两天我尝试仿照Golang正在设计一款协程库。
协程有什么用途呢?合理利用资源。通用的进程和线程模型都耗费了不应该耗费的资源,要想处理更多并发得自己管理任务切换。
我实现的协程比较简单。在设计过程中发现了两个小难点,分享给大家。
A 如何实现扩容
我们要压缩任务的内存空间,首要的措施就是在任务创建开始不给它过多的内存。但是任务需要更多的内存的时候呢?这就是涉及到了扩容:Golang如何处理扩容的呢?
它不允许直接的指针操作,所以它可以通过移动内存和其上的数据达成目的。
C语言肯定是限制不了了。
如何获得用户即将超过栈的消息?
C语言编译会对 可能超过栈的操作 建立一个栈检查,防止其越过栅栏页,此外通过栅栏页来使我们能够侦测到超出栈但是不超出一个页面的行为。
我采用的是Windows系统提供的预订和调拨内存操作。详细内容可参考:《Windows核心编程第五版》
预订不占用内存,只是占号码范围,我们知道虚拟内容是假的。
所以方法是这样:
给每个协程单元预订足够的内容(比如,像线程的默认大小一样1M)。
实际**调拨**4kb。
这样还顺带解决栅栏页的问题,因为未被调拨的空间访问,返回AV异常。我们接到这个异常然后判断范围后就去尝试调拨。
B 协程状态的保存与恢复
要给协程一个主动让出时间片机制,比较重要。举个例子:
协程A执行甲乙两个阻塞任务。
但乙操作预计属于可等待操作,可以让出时间片。
Windows的做法是:
Sleep(0),SwitchToThread()
怎么在R3实现这个操作呢?
通过触发异常我们可以获取完整的信息,但是这个操作太费时间,所以我设计了一段汇编来完成我们的任务:
我们只需要保存:
1. `pushad`:保存除IP外的寄存器到栈 2. `pushfd`:保护符号寄存器到栈 3. `call 0`:保存ip到栈
OK。
下面是详细流程:
A. 如何实现协程扩容?√
通知机制
安置栅栏页扩容
预订和调拨物理存储器//Windows核心编程第五版预订地址空间区域,给区域调拨来自页交换文件的物理存储器。
根据自己的需要来设置页面的保护属性。
/*预订地址空间区域*/ VirtualAlloc( /*想要的地址:分配粒度:64kb倍数,向下取整*/, /*大小, 分配粒度按照CPU页面大小。一般是4kb?*/, MEM_RESERVE/*预订*/, PAGE_EXECUTE_READWRITE ) /*调拨物理存储器*/ VirtualAlloc((PVOID)Address/*开始地址*/,/*调拨数量*/, MEMCOMMIT,PAGE_READWRITE)
B. 协程状态保存与恢复√
状态有哪些?如何恢复?
esp ebp eax ebx ecx edx esi edi eip flags 漂亮的命令有: pushad: 将所有的32位通用寄存器压入堆栈,只对ESP有影响 压入顺序(从低地址到高地址): eax,ecx,edx,ebx,esp,ebp,esi,edi pushfd: 将32位标志寄存器EFLAGS压入堆栈
什么形式探测这些状态?
内联函数非常快速,但是要考虑如何安排数据
pushad:保存除IP外的寄存器
pushfd:保护符号寄存器
call 0:保存ip并计算出下次执行应该开始的地方,然后push
jmp到收集栈的流程。
内联异常
这是一种非常好的方式。但是涉及异常,影响速度?
相关文章推荐
- 两个需要解决的问题
- 12个需要注意的规范样式写法解决浏览器兼容问题
- 第九章:重载赋值运算符中需要注意的两个问题
- 使用OpenSessionInView解决懒加载需要注意的问题
- UI设计中需要注意的十二个问题 ---来自OFFIDEA DESIGN
- (转)ASIC设计中各个阶段需要注意的问题——节选
- 【struts2】开发过程中遇到的需要注意的小问题的原因与解决方法
- 分布式需要注意的问题和解决办法
- Active Directory 设计需要注意的问题
- 如何比较Keras, TensorLayer, TFLearn ?——如果只是想玩玩深度学习,想快速上手 -- Keras 如果工作中需要解决内部问题,想快速见效果 -- TFLearn 或者 Tensorlayer 如果正式发布的产品和业务,自己设计网络模型,需要持续开发和维护 -- Tensorlayer
- this引出的上下行转换和类继承体系设计需要注意的问题
- PHP的foreach中使用引用时需要注意的一个问题和解决方法
- 在代码中设置ListView的divider,需要注意的两个问题
- 我在安装TFS 2008的时候遇到的问题以及解决方法一安装TFS需要注意的地方
- 重载赋值运算符中需要注意的两个问题
- 网络爬虫设计中需要注意的几个问题
- 网络数据传输需要注意的两个问题
- 【天天问每周精选】第14期:电商产品的设计和运营需要注意哪些问题?
- Tcp流套接字两个需要注意的问题:粘包和包分段
- Android APP设计加载使用gif动图需要注意的一般性问题