Linux同步和异步-事件循环

请问下:

linux如何实现,nginx是如何实现异步的?在哪个地方体现了
    1.进程同步和异步
    2.线程的同步和异步
    3.事件循环到底是什么意思?如何定义什么叫事件的?比如swoole说的事件驱动
我学了一年了,都没搞明白。

如果说进程程序一直执行叫同步,那么异步是如何实现的?
比如nginx内部读取图片,是不是开一个线程或者进程,这样和父进程没有关系了就叫异步?
线程的同步,有相关函数通过信号来支持,比如锁。那么异步是如何支持的?

希望大佬能用代码 或者函数指定下,谢谢!
阅读 3.3k
1 个回答

说下自己的理解,供参考。假设题主了解网络编程和计算机系统的一些基本概念。

简单概括来说,事件驱动是实现并发处理的一种方式。

我们就以HTTP请求的处理过程为例,为简化说明,仅考虑网络IO,不考虑文件IO和数据库等其他过程,也不考虑多核系统。
考虑采用如下最简模型来处理HTTP请求:

main_loop:
  accept() 
  recv()  
  parse() 
  send() 
  close() 

来一个连接,读取数据(请求),解析请求内容,返回数据(应答)。
同一时间只为一个客户端服务。在为A客户端服务的过程中,B客户端必须等待。

这种方式非常简单直接,容易理解,但其无法满足现实场景的需要——不支持并发
现实中,客户端的请求是并发的:即当一个客户端的请求还在处理时,另外一个客户端的请求就会达到,甚至多个客户端的请求同时达到。
而且,recv 和 send等涉及网络操作的API由于网络数据发送与到达的不确定性,可能需要等待,CPU会空闲下来——但这种模型下即使CPU空闲了也无法处理其他客户端的请求,浪费了CPU。

我们采用如下多线程模型,可以解决上述问题:

main_loop:
  accept() 
  start_thread(thread_loop)

thread_loop:    
    recv()  
    parse() 
    send() 
    close() 
    exit thread()

即每个客户端在一个独立的线程中处理。
当一个客户端的线程执行网络操作需要等待时,会被操作系统调度出去,执行其他需要干活儿的线程。
似乎完美了解决了我们的问题?
然而并没有。
因为操作系统创建线程的开销是比较大的,能够支持的线程数量是有限的,通常是几万的级别,如果线程太多,就会有很多的CPU浪费在了线程的创建、销毁、调度等管理操作上。

所以为了充分发挥CPU的能力,支持更多的并发数量,,在Linux上有另外一种处理并发的方式:
内核提供了监听大量网络连接(句柄)可读、可写等事件的机制和接口。
应用把需要监听对象以及关心的事件注册给内核,内核在有事件达到时通知应用处理。
基于这种机制处理并发就是事件驱动。

事件驱动机制的基本模型是:

create_listen_socket()
register_event_for_listen_socket()
main_loop:
    wait_for_event()
    check_events:
         if listen_socket has event(new client coming) :
               accept()
               register_event_for_client_socket()
        if client_socket has event(new data coming):
               recv()                       
               parse()
               send()              

但这里有一个问题,有可能一个客户端刚读取了一部分数据,就没了,剩下的还在网络中没过来,需要继续等待。
这就需要把当前的读取内容和请求处理状态(也即上下文)保存起来,继续处理其他客户端的事件。
然后下次这个客户端再有事件到来时再找回上下文继续处理。
这其实需要应用自己做一些任务调度相关的上下文保存和切换工作。

当使用多线程处理并发时,操作系统帮我们做了这些工作,我们无需关心任务切换。
因为一个线程就只处理一个客户端,反复调用recv把一个请求的数据读完然后解析处理就可以了,也不用担心没数据到来时,recv阻塞了其他客户端的处理。
所以多线程编写并发代码非常简单直接。

如上,事件驱动机制是Linux上解决并发问题的一种高效编程模型。
应用反复探测事件,对接收到的事件进行逐个处理的过程就是事件循环。

那么同步和异步概念体现在哪里呢?

所谓同步就是我们执行一个任务,一直等待任务执行结束。
所谓异步就是我们执行一个任务,不等待任务执行结束,继续去干其他活儿,任务结果后有个通知,或者干脆不关心任务的执行结果。

在多线程模型中,每接收到一个新的客户端就创建一个线程处理,这就是一种异步处理。
在事件驱动模型中,当没有数据可读时,就把这个客户端继续放到监听队列中监听,也是一种异步。

如果我们考虑文件IO,把IO请求丢给另外一个或一组线程(线程池)处理,处理完后通知主线程,也是一种异步。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题