`
zsxxsz
  • 浏览: 452154 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

网络协程编程

阅读更多

一、背景

 为什么需要网络协程?

1、协程/纤程并不是一个新概念
2、大并发、高性能对于服务端的高要求
3、移动设备的快速增长加大了服务端大并发压力
4、Go 语言的兴起将协程带到了一个新的高度

支持协程的编程语言:
1、Go 语言,非常容易支持大并发、高性能
2、Python 语言
3、Erlang 语言
4、Lua 语言
。。。。。。

为什么要设计一套 C/C++ 网络协程库?
1、学习一部门语言的成本要远高于学习一个库
2、C/C++ 程序员多年的经验积累损耗巨大
3、C/C++ 综合运行效率高
二、关于并发
 - 虽已进入多核时代,但服务器的 CPU 核心总是有限的
 - 当进程/线程数越多操作系统的调度算法就越低效
 - TCP长连接及连接池的存在,造成服务端80%以上的连接是空闲的

为支持并发,我们需要采用:
1、多进程模式:支持并发能力非常有限,如 Postfix,Xinetd;
2、多线程模式:比多进程模式有提高,但依然有限,如 Mysql;
3、非阻塞模式:性能高,但编程复杂度极高,如 Nginx,Redis;
4、基于事件的多线程模式:并发度有较大提高,但编程提升依然有限,如 acl 中的 master_threads 服务模式;
三、设计目标
 我们需要一种新的编程模式来满足C/C++程序员:
1、支持大并发、高性能,较低的资源使用率
2、较低的编程复杂度:顺序思维模式
3、适合多数应用场景,提供丰富且简单易用的接口
4、与第三方网络库无缝集成,无需修改第三方库
四、一个简单的协程示例
1、创建协程类似于创建线程
2、支持大并发、高性能
3、顺序性编程方式
4、无需更改第三方库
5、仅使用一个线程资源

 五、协程的调度方式

 1、上下文切换
 通过操作系统提供的 API 完成:getcontext、makecontext、swapcontext、setcontext;
 或 自己通过汇编语言来实现协程运行栈空间的切换
 实现库举例:libtask,boost,libgo, libco,coroutine  等

 2、信号跳转
 通过系统提供的 API 完成:siglongjmp、longjmp、setjmp、sigsetjmp 等
 实现库举例:libmill,st ,coroutine 等

 

六、协程切换方式


 

七、网络协程调度


 

1、IO事件协程监控所有的IO事件
2、网络协程运行时遇到IO阻塞,则被挂起,其IO句柄由IO事件协程监控
3、IO事件发生时,其绑定的协程被再次唤醒

 

八、如何与第三方库无缝集成

1、HOOK IO相关API
读 API:read/readv/recv/recvfrom/recvmsg
写 API:write/writev/send/sendto/sendmsg
其它 API:pipe/popen/pclose/open/close/fcntl
2、HOOK 网络相关API
socket/socketpair/bind/listen/accept/connect
poll/select/epoll_create/epoll_wait/epoll_ctl
gethostbyname/gethostbyname_r

通过 HOOK 系统底层 API,可以实现:
1、直接接管第三方库(如:mysql/http/redis 等库)的网络连接及通信过程
2、直接接管第三方库的域名解析过程
3、将第三方网络阻塞过程协程化,在协程库底层转化为非阻塞过程

 

将mysql库协程化的例子参见:acl/lib_fiber/samples/mysql

 

九、为何要 HOOK 很多系统API

1、poll/select 为网络编程中常用系统 API
2、很多第三方网络库用 poll/select 模拟IO超时
3、epoll 在 reactor 类应用(如:聊天)方面比较广泛
4、gethostbyname 在域名解析方面应用广泛
5、listen 需要将监听描述字设为非阻塞模式
6、connect 需要将连接描述字设为非阻塞模式
7、bind/socket/socketpair/。。。为便于将出错号与协程绑定
 

十、基于协程的 errno

因为每个线程中存在大量协程,当某个协程的IO过程出错时,如果实现不同协程之间的 errno 是相互隔离的?
--- 在 Linux 平台下直接 HOOK __errno_location 系统函数
参见:/usr/include/bits/errno.h

extern int *__errno_location (void) __THROW __attribute__ ((__const__));
#define errno (*__errno_location ())

针对进程内全局变量:errno,操作系统将该变量定义为一个函数指针地址,函数内部会通过线程局部变量方式给每一个线程分配一个 error 对象
因此,通过 hook __errno_location 函数,在协程库里给每个协程一个协程局部变量,实现了 errno 全局变量的协程安全性

 

十一、内存安全检测

配合 valgrind 做内存检测:
- valgrind 与 xxxcontext 的不兼容性
- 需下载 valgrind 开发包,调用 VALGRIND_STACK_REGISTER通知
  valgrind 跳过检测该内存区域
- 检测时在 Makefile 里打开 –DUSE_VALGRIND 编译选项,重新编译 lib_fiber.a

 

十二、有效使用多核

 每个线程一个独立的协程调度器,通过创建多个线程使用多核
使用 acl master 服务器框架,创建多进程使用多核,每个进程一个协程调度器

多线程示例参见:acl/lib_fiber/samples/redis_threads
多进程示例参见:acl/lib_fiber/samples/master_fiber

 

十三、协程同步原语



 

基于协程的协程锁:
1、协程互斥锁
2、协程读写锁

 

十四、协程挂起与唤醒

-- 协程挂起方式
1、主动让出 CPU 控制权
当前运行的协程通过调用 acl_fiber_yield 主动让出 CPU 控制权,协程调度器调用别的协程
2、指定休眠时间
当前运行的协程通过调用 acl_fiber_sleep 使当前协程休眠指定时间
3、IO阻塞被挂起
当前运行的协程等待IO完成时,需要将自身挂起

-- 协程唤醒方式
1、主动 yield 的协程又重新获得 CPU 控制权
2、处于休眠状态的协程时间到达
3、因IO阻塞而被挂起的协程因IO准备好而被唤醒

示例参考:
1、yield 方式:acl/lib_fiber/samples/fiber
2、sleep 方式:acl/lib_fiber/samples/sleep
3、IO 方式:acl/lib_fiber/samples/select

 

十五、过载保护


 

十六、协程间通信

协程间为什么需要通信?
1、业务逻辑的模块化
2、业务模块的分层设计
3、团队开发的协作性

协程间“通信”的本质:
- 协程间数据的传递通过协程上下文的切换,本质上是协程间的数据交换

协程间“通信”的成本:
1、协程上下文切换
2、内存分配、释放
3、数据拷贝

协程间“通信”方式:
- 支持多对多数据交互



- 协程通信管道支持多对多方式
- 协程间通信通过切换协程上下文及数据交换完成
- 协程间通信时的数据交换支持缓冲模式
- 协程间通信时的数据交换采用随机分配方式

十七、线程间通信

协程模式下为何需要线程间通信?
- 为使用多核,开启多个线程,线程间需要交换数据
- 有些任务需要在线程池里异步完成,结果需要传递给主线程

协程模式下线程间的通信方式:
- 无锁消息队列 + IO 模式

 

十八、线程间通信


1、生产者/消费者之间优先通过无锁队列进行数据传递
2、当生产者无数据时,消费者通过IO堵塞
3、当消费者堵塞在IO等待新消息时,生产者若有新消息则通过IO通知消费者
4、无锁队列利用率越高,则处理性能越高

 

十九、应用场景

(一)、问答式应用服务
基于 HTTP 协议的服务应用,诸如:网站
基于 SMTP/POP3/IMAP 协议的服务应用
(二)、生产者 – 消费者类应用服务
如消息队列类应用
(三)、reactor 和 proactor 两种模式的结合
统一的事件引擎监控所有的网络连接,有一个连接就绪时创建协程独立处理
此类应用如聊天服务、游戏服务等无状态的应用服务
(四)、大并发类应用服务
因为通过协程方式,将上层应用的堵塞式在底层转为非阻塞模式,所以非常容易以较低资源支持大并发类应用
如内网的多数应用服务为提高效率都支持连接池模式,需要服务端支持非常大的并发
(五)、网络限流
在协程中可以直接 sleep,非常容易控制网络流量

 

二十、协程编程注意事项

(一)、协程运行堆栈空间的合理分配
每个协程都需要分配一定的内存空间用于上下文的切换,如果分配大了则会造成内存浪费,分配小了可能造成意外不可恢复的崩溃
一般情况下,每个协程分配32KB ~ 320KB

(二)、协程间需要协作,防止有的忙死,有的饿死
当协程长期占用 CPU 时,应该主动 yield 让出 CPU

(三)、协程内防止有堵塞式操作,以防堵塞当前线程中的所有协程
应通过对业务逻辑模块进行分类,确定不同的协程工作方式,使堵塞操作放在线程池中运行

 

二十一、参考

 

 基于协程的简单网络服务:使用 acl 协程编写高并发网络服务

 基于协程的 WEB 服务:使用协程方式编写高并发的 WEB 服务

 协程库:https://github.com/acl-dev/acl/tree/master/lib_fiber

 acl svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code

 acl github:https://github.com/acl-dev/acl

 acl 国内镜像:http://git.oschina.net/acl-dev/acl/

 qq 群242722074

 微博:http://weibo.com/zsxxsz/

 

  • 大小: 55 KB
  • 大小: 17 KB
  • 大小: 21.9 KB
  • 大小: 24.5 KB
  • 大小: 50.5 KB
  • 大小: 26.6 KB
  • 大小: 20.6 KB
  • 大小: 7.7 KB
1
1
分享到:
评论

相关推荐

    基于协程编程在移动端研发的最佳实践.pptx

    协程编程在移动端研发中扮演着重要的角色,尤其是在解决高性能应用的性能瓶颈和代码可维护性问题方面。本文将深入探讨协程的概念、实现原理、最佳实践,以及它们如何改善移动端应用的性能。 首先,传统的多线程编程...

    基于协程的网络编程库 QtNetworkNg.zip

    在给定的压缩包“QtNetworkNg.zip”中,包含的源代码着重于使用协程(Coroutines)改进Qt的网络编程模块,即QtNetworkNg。这个库是针对Qt原生网络模块的扩展,旨在提供更高效、异步的网络通信解决方案。 协程是一种...

    基于Kotlin协程实现异步编程.zip

    本压缩包文件“基于Kotlin协程实现异步编程.zip”包含了一份详细讲解如何使用Kotlin协程进行异步编程的PDF文档,以下是其主要知识点的详述。 **1. Kotlin协程基础知识** Kotlin协程是一种轻量级的线程机制,它们...

    Swoole2.0原生协程高性能开发实践

    标题中提到的“Swoole2.0原生协程高性能开发实践”揭示了在Swoole框架的2.0版本中,原生协程的概念和应用是如何在构建高性能...然而,这也要求开发者必须对PHP协程编程有较深入的了解,才能充分利用Swoole框架的特性。

    C++网络编程 卷1和卷2 以及Linux多线程服务端编程 - 陈硕(高清完整版)

    2. **并发编程**:讨论了线程池、事件驱动编程、协程等并发控制机制,提高服务端的性能和可扩展性。 3. **性能优化**:分析了网络程序的性能瓶颈,并给出了优化策略,如缓冲区管理、零拷贝技术等。 4. **设计模式与...

    libco协程库,附VS工程

    完善简洁的协程编程接口 类pthread接口设计,通过co_create、co_resume等简单清晰接口即可完成协程的创建与恢复; __thread的协程私有变量、协程间通信的协程信号量co_signal (New); 语言级别的lambda实现,结合协程...

    C++开源协程库libco-原理与应用

    相比之下,Go语言凭借其简洁的语法和内置的协程支持,简化了网络编程,并实现了极高的并发性能。 #### 重要概念:协程 **协程**是一种比进程更轻量级的并发模型,它允许程序在执行过程中挂起并恢复执行,而不是像...

    关于C语言协程与网络编程的分析

    总的来说,C语言中的协程和网络编程结合,能够提供一种更为高效和灵活的并发处理方案,尤其适合处理大量的并发连接和复杂的IO交互。通过理解和应用这些概念,开发者可以构建出更为健壮、性能优异的网络应用。

    python 网络编程和网络编程基础

    Python网络编程是现代软件开发中的重要组成部分,尤其在大数据、云计算和物联网等领域的应用日益广泛。本主题将深入探讨Python在网络编程方面的基础知识和实践技巧。 首先,Python的网络编程主要涉及套接字(socket...

    PYTHON网络编程基础.pdf

    此外,Python还提供了asyncio库来实现异步网络编程,这是Python 3.4引入的新特性,基于事件循环和协程。异步编程可以让程序在等待网络I/O操作时,执行其他任务,提高系统资源利用率和程序响应速度。使用asyncio,你...

    Python-用于在Python34中进行协程驱动的基于异步的泛型编程的小工具库

    随着Python 3.5引入了asyncio库,协程编程变得更加优雅,但在3.4版本中,类似的功能可能需要自定义的库来支持。 在“paco-master”这个压缩包中,我们可以预期找到以下内容: 1. **源代码文件**:库的核心代码可能...

    Android 基于协程OkHttp网络请求工具.zip

    本项目“Android 基于协程OkHttp网络请求工具”结合了这两者,旨在提供一种更加优雅、高效的网络请求解决方案。 1. **协程基础** - 协程是一种编程概念,允许开发者编写非阻塞式的并发代码,避免了线程切换的开销...

    我的博客中网络编程源码

    - **协程编程**:可能涉及Python的`asyncio`库或Java的`CompletableFuture`,实现非阻塞式的网络I/O操作。 - **Socket编程**:包含创建Socket,绑定端口,监听连接,接受客户端请求,以及发送和接收数据的示例代码。...

    Boost.Asio C++ 网络编程 中文版

    ### Boost.Asio C++ 网络编程知识点 #### Boost.Asio 入门 - **什么是Boost.Asio?** Boost.Asio是一个跨平台的C++库,用于网络和低级I/O编程。它提供了简单而强大的方式来处理异步I/O。 - **历史**:Boost.Asio的...

    基于协程的C++网络开发框架.zip

    本资源"基于协程的C++网络开发框架.zip"聚焦于利用协程来优化C++的网络编程,这在当前并发处理需求日益增长的环境中显得尤为关键。 首先,我们要理解什么是协程。协程是一种用户级的轻量级线程,它允许程序在执行...

    深入解析Go语言并发编程中的协程机制与应用场景

    Go语言作为Google公司开发的一种编程语言,其设计初衷是为了提供一种简单、高效、可靠的...无论是在网络编程、并发计算,还是大数据处理等领域,Go语言的协程都提供了高效的解决方案,使得编写并发程序更加容易和安全。

    C++ 开源协程库 libco——原理及应用1

    C++ 开源协程库 libco 正是这样一种工具,它为 C++ 开发者提供了类似 Go 语言中的协程功能,简化了高性能网络服务器的编程。 libco 是腾讯微信团队开发并广泛应用于后台服务的协程库,自 2013 年开源以来,已经在...

    系统编程_网络编程_web编程.rar

    3. 异步I/O:Python的`asyncio`库用于实现异步网络编程,包括协程(coroutine)和事件循环(event loop)的概念。 接下来是“Web编程”。Web服务器案例课件.pdf可能涵盖: 1. Web基础:HTTP协议,请求方法(GET, ...

    cpp-QtNetworkNg基于协程的QtC网络框架API比boostasio更简单

    QtNetworkNg 是一个基于协程的网络编程库。目标为 C 开发者提供简洁而不失强大的网络编程 API,成为 C 界最好的网络编程库。目前已经具备完善的协程管理功能、基本的 socket 编程和完善的 HTTP 1.1 客户端。

Global site tag (gtag.js) - Google Analytics