概述
1、libfiber介绍
首先说下为什么要写这个博客,一是记录自己学习,二是防止学习后遗忘,这样即使忘了还可以通过博客来回忆起一个大概
开源项目位置:
https://github.com/iqiyi/libfiber
libfiber中文介绍:
https://github.com/iqiyi/libfiber/blob/master/README_cn.md
开源团队:爱奇艺
相关协程的开源项目不少,boost,libco,libfiber等等
协程的概念在此就不说了,不过协程的实现可以简单说下,我只看过libco和libfiber这两个协程的代码,其中libco是由腾讯团队自己写的汇编实现的协程,协程本质其实是保存当前堆栈信息,然后创造出一个新的堆栈环境去执行(自己思考的,有错误望指出)
。而爱奇艺则是借助linux下给出的已有的接口,在此接口上进行一系列逻辑操作, 接口在头文件ucontext.h。
据爱奇艺给出的测评,libfiber性能高于libco。
// libco 实际切换上下文的代码
.globl coctx_swap
#if !defined( __APPLE__ )
.type coctx_swap, @function
#endif
coctx_swap:
#if defined(__i386__)
movl 4(%esp), %eax
movl %esp, 28(%eax)
movl %ebp, 24(%eax)
movl %esi, 20(%eax)
movl %edi, 16(%eax)
movl %edx, 12(%eax)
movl %ecx, 8(%eax)
movl %ebx, 4(%eax)
movl 8(%esp), %eax
movl 4(%eax), %ebx
movl 8(%eax), %ecx
movl 12(%eax), %edx
movl 16(%eax), %edi
movl 20(%eax), %esi
movl 24(%eax), %ebp
movl 28(%eax), %esp
ret
#elif defined(__x86_64__)
leaq (%rsp),%rax
movq %rax, 104(%rdi)
movq %rbx, 96(%rdi)
movq %rcx, 88(%rdi)
movq %rdx, 80(%rdi)
movq 0(%rax), %rax
movq %rax, 72(%rdi)
movq %rsi, 64(%rdi)
movq %rdi, 56(%rdi)
movq %rbp, 48(%rdi)
movq %r8, 40(%rdi)
movq %r9, 32(%rdi)
movq %r12, 24(%rdi)
movq %r13, 16(%rdi)
movq %r14, 8(%rdi)
movq %r15, (%rdi)
xorq %rax, %rax
movq 48(%rsi), %rbp
movq 104(%rsi), %rsp
movq (%rsi), %r15
movq 8(%rsi), %r14
movq 16(%rsi), %r13
movq 24(%rsi), %r12
movq 32(%rsi), %r9
movq 40(%rsi), %r8
movq 56(%rsi), %rdi
movq 80(%rsi), %rdx
movq 88(%rsi), %rcx
movq 96(%rsi), %rbx
leaq 8(%rsp), %rsp
pushq 72(%rsi)
movq 64(%rsi), %rsi
ret
#endif
// libfiber切换上下文代码
// 仅介绍linux下的
static void fiber_unix_swap(FIBER_UNIX *from, FIBER_UNIX *to)
{
#if defined(USE_BOOST_JMP)
swap_fcontext(from, to);
#elif defined(USE_JMP)
/* use setcontext() for the initial jump, as it allows us to set up
* a stack, but continue with longjmp() as it's much faster.
*/
if (SETJMP(&from->env) == 0) {
/* context just be used once for set up a stack, which will
* be freed in fiber_start. The context in __thread_fiber
* was set NULL.
*/
if (to->context != NULL) {
setcontext(to->context);
} else {
LONGJMP(&to->env);
}
}
#else
if (swapcontext(from->context, to->context) < 0) {
msg_fatal("%s(%d), %s: swapcontext error %s",
__FILE__, __LINE__, __FUNCTION__, last_serror());
}
#endif
}
2、IO相关
协程的用途一般多用于IO,以同步的方式做异步事情。故无论在libco还是libfiber都有hook系统API的操作,但自己看了两个协程开源项目后不明白为什么要hook系统API,设置无阻塞可以通过setnonblock来操作,为什么还要hook系统IO呢?
这篇博客有介绍,但自己未实际操作过,所以一知半解。
https://blog.csdn.net/zsxxsz/article/details/88349461
3、环境及用途
libfiber提供了C和C++两种API,但实际C++调用的还是C的代码,故只需要看懂C的协程实现即可。
协程是用户级线程,由用户来管理,解决了CPU 上下文切换的开销,协程不适用于计算密集型的项目,因为计算密集型cpu会很少切换,所以协程的优点也就不存在,反而还增加了开发难度,但对于一个web服务器来说,其优势是绝对的。
4、协程
1、协程创建
/**
* @brief 创建一个协程所需的资源
* @param fn 协程执行函数
* @param arg fn的参数,类似pthread_create的第四个参数
* @param size 协程运行环境的堆栈大小
*/
ACL_FIBER *acl_fiber_create(void (*fn)(ACL_FIBER *, void *),
void *arg, size_t size)
{
ACL_FIBER *fiber = fiber_alloc(fn, arg, size);
// __thread_fiber是线程所有,存活周期为线程存活时长
// c由关键字__thread支持,cpp由thread_local支持
// 此变量的作用相当于是为每个线程都创建一个主协程,
// 主协程的作用就是管理在本线程创建的协程
// __thread_fiber在fiber_check()中初始化,fiber_alloc和acl_fiber_schedule均有调用
// 故为线程创建第一个用户协程时会先创建__thread_fiber
__thread_fiber->count++;
if (__thread_fiber->slot >= __thread_fiber->size) {
__thread_fiber->size += 128;
__thread_fiber->fibers = (ACL_FIBER **) mem_realloc(
__thread_fiber->fibers,
__thread_fiber->size * sizeof(ACL_FIBER *));
}
// __thread_fiber->slot是一个用户协程计数器,表示当前有多少个协程
// 将新建的协程放进数组
fiber->slot = __thread_fiber->slot;
__thread_fiber->fibers[__thread_fiber->slot++] = fiber;
acl_fiber_ready(fiber);
if (__schedule_auto && !acl_fiber_scheduled()) {
acl_fiber_schedule();
}
return fiber;
}
未完待续…
最后
以上就是朴实机器猫为你收集整理的读爱奇艺开源协程项目—libfiber的全部内容,希望文章能够帮你解决读爱奇艺开源协程项目—libfiber所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复