读爱奇艺开源协程项目—libfiber

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;
}

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值