协程知识点总结

简介: 协程知识点总结

思路

先理解

  • Select / poll /epoll ? 基于事件驱动来做的 io 复用
  • Reactor ? 用epoll来封装的反应堆
  • Http 网络http协议 协议头 如何实现内部 get cgi
  • Webserver ? 做一个网络的服务端 基于reactor
  • 单线程 多线程 多进程reactor?
  • Posix api 和协议栈 tcp协议栈
  • Udp 协议 kcp

在理解

  • 为什么会有协程?解决什么问题?同步的线程 异步的操作
  • 原语操作有哪些?同步和异步的切换 操作中最基本的单位eg createyelid resume
  • 切换 (Switch)类似于线程 进程的切换
  • 协程的运行流程
  • 协程结构体定义
  • 调度策略 类似于 进程调度 lua算法等一系列的策略 cfs
  • 调度器如何定义?
  • 协程 api 的实现,hook?
  • 多核模式
  • 如何测试?

注意: 没有特别声明fdsockfd连接io 指的都是 fd!!!

为什么会有协程?解决什么问题?

  • 理解什么是同步什么是异步?
  • 理解什么是同步的编程方式异步的性能?同步的编程方式和异步的编程方式的优缺点是什么?
  • 为什么异步的编程方式避免不了多个线程共用一个 fd?导致数据乱序?
  • 适用于服务器与客户端异步处理。

IO 同步、异步操作对比

站在服务器端

比如 reactor 监听时间。

同步 7.5s 连接1000个 。

异步 1.4s 连接1000个。

//同步
while(1)
{
  epoll_wait
    For(;;)
  {
    Recv();
    Send();
  }
}
//异步
Push_other_thread()
{
  Poll(); //检测 可读可写  治标不治本 不能根除 多个线程同用一个fd
  Recv();
  Send();
}
While(1)
{
  Epoll_wait();
  For(;;)
  {
    Push_other_thread();
  }
}

分析:

  • Io 异步的问题 push_other_thread 避免不了多个线程公用一个fd的现象 尽量的去避免
  • 问题乱序读的数据不对 A再读 B 关闭。莫名其妙的就出现问题 ,如何解决线程前加poll再次检测但是治标不治本 。

站在客户端的角度

客户端发送之后等待服务端的结果,发送50个域名给客户端进行请求同步的没异步的处理快。

总结不管是再客户端还是服务端 io异步的性能总是快。

通过站在客户端与服务器端推出:

协程就是解决了同步的性能,异步的共用现象使用同步的编程,却实现了异步的操作处理

如何把同步的编程变成异步的呢?

正常的流程如下:

  1. 建立连接
  1. 当客户端发送一个请求到服务端时候,send();
  2. Epoll_wait判断是否可读;
  3. 等待服务端一个回发数据recv() (不可读会阻塞)同步,再去做一系列的操作

改成如下:

  1. 建立连接
  2. 当客户端发送一个请求到服务端时候send(),send之后切换成epoll_wait, if(不可读){ 开另外一个流程再次send },相当于异步操作 开了另外一个io口去做send ,epoll_wait判断是否可读.
  3. 等待服务端一个回发数据recv() (不可读会阻塞) 但是不影响上面,因为上面会切换另外一个请求去再次处理其他的send,再去做一系列的操作。
  4. 在send完毕后做一个切换到epoll_wait去判断fd是否可读不可读,让出回到主线程,去另外一个流程中再次send

总结:

先理解io操作io检测核心:遇到 io 操作就 yeid

send() 一次 fd ----》 利用epoll_ctl()加入epoll_wait()中检测 ----》 yeid(让出)跳入到epoll_wait()检测 if(可读){ recv() , 继续epoll_wait()检测} else { resume()}

切换(Switch)

  • yield:IO 操作 ----》 IO 检测
  • resume:IO 检测 ----》 IO 操作

协程入口函数

server_reader -> nty_recv -> nty_poll_inner -> nty_schedule_sched_wait -> _nty_coroutine_yield

协程结构体定义

举例:以客户端与服务器连接时,客户端流程

void client_func()
{
    send(fd, buffer, length, 0);
    int nready = epoll_wait(epfd, ); //加一个判断把同步的流程改成异步;
    recv(fd, rbuffer, length, 0);  //阻塞住  不要的
    //....
    //parser()解析服务端返回的数据
}

协程结构体定义

//用宏写 C++ 模板
#define queue_node(name type) struct name{\  
    struct type *next;
    struct type *prev;
}
#define rbtree_node(name type) struct name{\
    char color;
    struct type *right;
    struct type *left
    struct parents;
}
struct cpi_register_set
{
    void* eax; //寄存器上下文
    void* ebx; //寄存器上下文
    ....
};
struct coroutine
{
  // 类比线程 来定义协程需要的结构
    struct cpi_register_set *set; //保存cpu
    void *coroutine  e_create;// entry 协程入口函数
    void *arg; // 参数
    void *reval; //返回值 不做计算的话没什么意义
  // 函数调用如何调用?  利用栈
    void *stack_addr; //指向栈空间的首地址,在堆上开辟一个空间当做栈
    size_t stack_size;
  // 协程的数量很多 要用什么结构来储存   
  // 从调度器的角度来看  栈的格式不符合(会导致最底部的协程调用不到)stack_coroutine *next;
  // 队列的格式来用  
    queue_node(ready_name,coroutine) *ready;
    rbtree_node(wait_name,coroutine) *wait;
    rbtree_node(sleep_name,coroutine) *sleep;
}co;

协程的创建类比线程的创建

pthread_create(thid, NULL, entry_cb, arg) { }  //线程id, 线程属性(堆栈大小的参数),线程入口函数,参数
只做了两件事情:
1. 创建一个线程实体:task_struct *task;
2. 加入就绪队列 :enqueue_ready;
//协程创建
oroutine_create(entry_cb,arg);
coroutine_join(coid,&reval)  //获取子线程返回的值
{
    co = search(coid)
    if(co->reval ==NULL){
        wait(); //单线程 用条件等待
    }
    return co->reval;    
}
exec(co){
    //启动了协程函数 取得返回值
    co->reval = co->func(co->arg)
    //存到了协程的结构体里
    signal();//  
}

调度策略

调度器

//调度器
struct scheduler{
    struct scheduler_ops *ops;
    //当前运行的协程  当调度器让出的时候、
    struct coroutine *cur;  //当前哪个协程
    int epfd;  //
    queue_node *ready_set;
    rbtree() *wait_set;
    rbtree() *sleep_set;
}

协程 api 的实现,hook?

  • socketbindlistenconnectacceptsendrecv 同步改为异步
  • 利用 hook 函数
//异步api
void my_accept(){
    int ret=Poll(fd);
    if(ret>0){
        //就绪后 调用真正的accept
        accept();
    }
    else{
        //吧fd加入到epoll 后   “让出”   epoll管理
        epoll_ctl(epfd);   //time out 值设成0 立刻返回 做成异步的操作
        yield();       //调度器用
    }
}

hook 是把代码段中的改变 在进程开启阶段会调用inin_hook(),把函数内部 把系统调用对应的 指定函数 (send/recv)改成(send_f/recv_f)。

在应用下 用到了send(普通函数了)或者recv(普通函数了) 会自动的调用send_f/recv_f替换。

Yield之后如何执行 yield和resume如何实现的呢?让出到对应的resume下 resume到对应的yield下。

充电站

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习


相关文章
|
21天前
|
调度 Python
python知识点100篇系列(20)-python协程与异步编程asyncio
【10月更文挑战第8天】协程(Coroutine)是一种用户态内的上下文切换技术,通过单线程实现代码块间的切换执行。Python中实现协程的方法包括yield、asyncio模块及async/await关键字。其中,async/await结合asyncio模块可更便捷地编写和管理协程,支持异步IO操作,提高程序并发性能。协程函数、协程对象、Task对象等是其核心概念。
|
5月前
|
图形学
【unity知识点】Unity 协程/携程Coroutine
【unity知识点】Unity 协程/携程Coroutine
325 0
|
6月前
|
网络协议 应用服务中间件 Linux
日常知识点之网络面试八股文(tcp,惊群现象,协程)
日常知识点之网络面试八股文(tcp,惊群现象,协程)
124 0
|
设计模式 前端开发 编译器
Android体系课之--Kotlin协程进阶篇-协程中关键知识点梳理(二)
笔者在写这篇文章之前,也白嫖了很多关于Kotlin协程的文章: 这里笔者将他们分为三种: 1.讲的内容很*浅*,没几句可能就结束了,看完就索然无味了 2.讲的内容很*深*,看到一半就开始晕乎乎了,然后可能还是手机好玩。。 3.内容比较*适中*,读者可以在里面获取到一些协程的基本信息,关键内容可能就浅尝辄止了,很难获取到核心知识点 > 知识的学习就像谈恋爱,不能一上来就想和对方深入了解,也不能聊得太浅,影响后续发展,得讲究循序渐进。 接下来笔者会根据由浅入深的方式,阶段性来讲解Kotlin协程相关知识点。读者可以根据自己的需求,选择对应的阶段文章
|
5月前
|
Go Python
使用python实现一个用户态协程
【6月更文挑战第28天】本文探讨了如何在Python中实现类似Golang中协程(goroutines)和通道(channels)的概念。文章最后提到了`wait_for`函数在处理超时和取消操作中的作
50 1
使用python实现一个用户态协程
|
2月前
|
调度 Python
python3 协程实战(python3经典编程案例)
该文章通过多个实战案例介绍了如何在Python3中使用协程来提高I/O密集型应用的性能,利用asyncio库以及async/await语法来编写高效的异步代码。
20 0
|
4月前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
83 10
|
4月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
【7月更文挑战第15天】Python 3.5+引入的协程和异步函数革新了并发编程。协程,轻量级线程,由程序控制切换,降低开销。异步函数是协程的高级形式,允许等待异步操作。通过`asyncio`库,如示例所示,能并发执行任务,提高I/O密集型任务效率,实现并发而非并行,优化CPU利用率。理解和掌握这些工具对于构建高效网络应用至关重要。
48 6
|
4月前
|
大数据 数据处理 API
性能飞跃:Python协程与异步函数在数据处理中的高效应用
【7月更文挑战第15天】在大数据时代,Python的协程和异步函数解决了同步编程的性能瓶颈问题。同步编程在处理I/O密集型任务时效率低下,而Python的`asyncio`库支持的异步编程利用协程实现并发,通过`async def`和`await`避免了不必要的等待,提升了CPU利用率。例如,从多个API获取数据,异步方式使用`aiohttp`并发请求,显著提高了效率。掌握异步编程对于高效处理大规模数据至关重要。
52 4
|
4月前
|
设计模式 机器学习/深度学习 测试技术
设计模式转型:从传统同步到Python协程异步编程的实践与思考
【7月更文挑战第15天】探索从同步到Python协程异步编程的转变,异步处理I/O密集型任务提升效率。async/await关键词定义异步函数,asyncio库管理事件循环。面对挑战,如思维转变、错误处理和调试,可通过逐步迁移、学习资源、编写测试和使用辅助库来适应。通过实践和学习,开发者能有效优化性能和响应速度。
51 3