tbox协程使用之切换与等待
tbox的协程实现,是stackfull模式的,需要指定独立堆栈和协程函数,目前暂时还不能像golang那样实现堆栈的动态增长,之后会对其进行支持。
目前提供下面一些功能特性:
1. 提供yield切换调度支持,这个是必须的哈
2. 提供suspend(挂起)/resume(恢复)协程接口,不同于yield的是,被suspend后,如果不显示调用resume恢复它,是永远不会被调度到的
3. 提供sleep等待接口支持
4. 提供io调度支持,支持socket等io等待(内部使用epoll, poll, kqueue, select, poll等接口调度)
5. 原生支持stream,socket,http等模块的协程支持,可与线程进行无缝切换
6. 提供channel同道,进行协程间交互通信
7. 提供lock,semaphore等接口
这里主要讲讲,基础的切换调度如何使用。。
yield切换
这个的使用非常简单,直接上代码吧,嘿嘿。。
static tb_void_t switchfunc(tb_cpointer_t priv)
{
// 获取传入的参数
tb_size_t count = (tb_size_t)priv;
while (count--)
{
// 打印当前协程id
tb_trace_i("[coroutine: %p]: %lu", tb_coroutine_self(), count);
// 让出当前协程,进行切换
tb_coroutine_yield();
}
}
tb_int_t main(tb_int_t argc, tb_char_t** argv)
{
// 初始化tbox
if (!tb_init(tb_null, tb_null)) return -1;
// 初始化一个调度器实例
tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init();
if (scheduler)
{
// 开启一个协程,传递switchfunc切换函数和参数10,最后一个参数指定栈大小,传0使用默认值
tb_coroutine_start(scheduler, switchfunc, (tb_cpointer_t)10, 0);
// 开启协程,使用指定的栈大小:8192
tb_coroutine_start(scheduler, switchfunc, (tb_cpointer_t)10, 8192);
/* 运行调用,开始运行里面的所有协程
*
* 第二个参数指定是否启用独占模式,这个稍后细讲
*/
tb_co_scheduler_loop(scheduler, tb_true);
// 退出调度器
tb_co_scheduler_exit(scheduler);
}
// 退出tbox
tb_exit();
}
所有协程执行完后,就会从loop调用处返回,当然在协程函数内部也是可以嵌套开启新协程的
这个时候第一个参数就不需要显示指定scheduler了,传tb_null
表示在当前调度器环境中开新协程,例如:
static tb_void_t switchfunc2(tb_cpointer_t priv)
{
// ..
}
static tb_void_t switchfunc(tb_cpointer_t priv)
{
// 在当前协程函数内,开启一个新协程
tb_coroutine_start(tb_null, switchfunc2, tb_null, 0);
// 获取传入的参数
tb_size_t count = (tb_size_t)priv;
while (count--)
{
// 让出当前协程,进行切换
tb_coroutine_yield();
}
}
独占模式
上面的代码中提到的独占模式,需要特殊说明下,一般情况下,传tb_false
到loop()中,不启用此模式是最为稳妥的。
因为这样每个scheduler对应的线程都会在Tls中维护自己的scheduler引用,使得协程中所有操作,都回去访问当前线程tls对应的独立scheduler,互不干涉。
这个在存在多个scheduler的情况,尤为重要,当时这样多少会有些tls操作上的性能损耗,像server端一般只有一个scheduler的情况下,就没必要放到独立tls中去了
可以传入tb_true启用独占模式,告诉tb_co_scheduler_loop(),我当前不需要tls维护,只需要一个全局scheduler变量来维护就行了
这样的话,性能会提升一些,因此在只有一个scheduler存在的情况下,启用独占效率会高些。。
sleep等待
tbox的tb_sleep
和tb_msleep()
接口,是可以原生支持协程的,在协程外就是线程等待,在协程内就是协程等待。
当然也可以直接使用协程的接口:tb_coroutine_sleep()
例如:
static tb_void_t sleepfunc(tb_cpointer_t priv)
{
while (1)
{
// 等待10ms,切换到其他协程,直到10ms后才会切换回来继续执行
tb_msleep(10);
}
}
resume/suspend接口
挂起域恢复,跟yield的区别就是,被suspend挂起的协程,默认是不会被切换调度回来的,除非执行resume恢复它。
因此这两个接口是成对使用的,像sleep,lock和semaphore的内部实现,也是基于此套接口。
这两个接口还有个功能,就是可以在两个协程间,更加快速方便的传递一些参数数据,进行交互,而不需要channel支持。。
例如:
static tb_void_t resumefunc(tb_cpointer_t priv)
{
// 获取suspend协程引用
tb_coroutine_ref_t coroutine = (tb_coroutine_ref_t)priv;
/* 恢复suspend协程,传递参数"hello suspend!"给suspend()作为其返回值
*
* retval为suspend()中传入的参数:"hello resume!"
*/
tb_char_t const* retval = tb_coroutine_resume(coroutine, "hello suspend!");
}
static tb_void_t suspendfunc(tb_cpointer_t priv)
{
// 开启一个恢复协程,传入当前协程引用
tb_coroutine_start(tb_null, resumefunc, tb_coroutine_self(), 0);
/* 挂起当前协程,传递参数"hello resume!"给resume()作为其返回值
*
* retval为resume()中传入的参数:"hello suspend!"
*/
tb_char_t const* retval = tb_coroutine_suspend("hello resume!");
}
当然,如果不需要交互数据,那么只需要传tb_null
就行了。。
个人主页:TBOOX开源工程
原文出处:http://tboox.org/cn/2016/10/29/coroutine-switch/
tbox协程使用之切换与等待的更多相关文章
- 并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_208 协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么 ...
- GJM : 进程、线程和协程的理解
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- Queue、进程、线程、协程
参考博客地址 http://www.cnblogs.com/alex3714/articles/5230609.html 1.python GIL全局解释器锁 python调用的操作系统的原生线程,当 ...
- 写个百万级别full-stack小型协程库——原理介绍
其实说什么百万千万级别都是虚的,下面给出实现原理和测试结果,原理很简单,我就不上图了: 原理:为了简单明了,只支持单线程,每个协程共享一个4K的空间(你可以用堆,用匿名内存映射或者直接开个数组也都是可 ...
- Python 协程总结
Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...
- Python并发编程协程(Coroutine)之Gevent
Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译 ...
- 再议Python协程——从yield到asyncio
协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...
- Golang 之协程详解
转自:https://www.cnblogs.com/liang1101/p/7285955.html 一.Golang 线程和协程的区别 备注:需要区分进程.线程(内核级线程).协程(用户级线程)三 ...
- 协程与Epoll的配合
想快速了解协程与网络调用的原来么,那么请赶紧关闭本页,因为下面都是在扯淡. 这几天是端午假期,第一天大算照着网上一大堆基于ucontext来写协程的文章自己也写一个简单的协程实现.于是第一天我就开始动 ...
随机推荐
- .NET的优点(转载)
一:什么是.NET?它包括什么? .Net是为简化在第三代因特网的高分布式环境下的应用程序开发,基于开放互联网标准和协议之上,实现异质语言和平台高度交互性,而构建的新一代计算和通信平台. .Net主要 ...
- Js中className的用法
className可以用来改变标签元素的css类选择器,从而改变元素的样式 举个栗子 一个简单的无序列表,点击button之前ul的样式为uhh1 点击button后,调用check函数中的class ...
- 第四讲 自定义Realm来实现身份认证
1.jdbcReam已经实现了从数据库中获取用户的验证信息,但是jdbcRealm灵活性太差.如果要实现自己的一些特殊应用时,将不能支持.这时,可以通过自定义Realm来实现身份的认证功能. 2.Re ...
- ps:图像格式的选择
从上面点阵与矢量两者的对比中,似乎矢量格式有优势,那为什么不都使用矢量格式呢? 这是因为矢量图像是基于线段的.因此它不适合记录色彩较为复杂的图像.如下图, 如果使用点阵方式来记录,只要按照顺序扫描并记 ...
- Linux 普通用户自动修改密码
在大量服务器运维中,维护服务器账号就让人头痛,对账号密码策略要求,现写了一个shell脚本来完成账号密码的修改,当然这个不是最好的方法,只是在没有其它辅助服务时使用,最好还是使用账户统一管理服务来维护 ...
- Flask之路由相关
1.装饰器中的参数 @app.route("/info", methods=["GET", "POST"]) def student_inf ...
- Django登录(含随机生成图片验证码)注册实例
登录,生成随机图片验证码 一.登录 - 随机生成图片验证码 1.随机生成验证码 Python随机生成图片验证码,需要使用PIL模块,安装方式如下: pip3 install pillow 1)创建图片 ...
- pandas.Series函数用法
class pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False) e.g., ...
- UVA 11178 Morley's Theorem (计算几何)
题目链接 lrj训练指南 P259 //==================================================================== Point getP( ...
- 20180705-Java基础语法
Java基础语法 一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条 ...