Python 中的进程、线程、协程、同步、异步、回调

本文深入探讨了Python中的并发编程概念,包括进程、线程、协程、同步、异步以及回调函数。详细解释了上下文切换技术,传统网络服务模型的优缺点,C10K问题的解决方案,多路复用技术如epoll的性能特点。此外,还讨论了用户态调度、协程与线程的关系,以及不同程序设计模型如回调模型和状态机模型的工作原理。
摘要由CSDN通过智能技术生成

进程和线程究竟是什么东西?传统网络服务模型是如何工作的?协程和线程的关系和区别有哪些?IO过程在什么时间发生?

在刚刚结束的 PyCon2014 上海站,来自七牛云存储的 Python 高级工程师许智翔带来了关于 Python 的分享《Python中的进程、线程、协程、同步、异步、回调》。

一、上下文切换技术

简述

在进一步之前,让我们先回顾一下各种上下文切换技术。

不过首先说明一点术语。当我们说“上下文”的时候,指的是程序在执行中的一个状态。通常我们会用调用栈来表示这个状态——栈记载了每个调用层级执行到哪里,还有执行时的环境情况等所有有关的信息。

当我们说“上下文切换”的时候,表达的是一种从一个上下文切换到另一个上下文执行的技术。而“调度”指的是决定哪个上下文可以获得接下去的CPU时间的方法。

进程

进程是一种古老而典型的上下文系统,每个进程有独立的地址空间,资源句柄,他们互相之间不发生干扰。

每个进程在内核中会有一个数据结构进行描述,我们称其为进程描述符。这些描述符包含了系统管理进程所需的信息,并且放在一个叫做任务队列的队列里面。

很显然,当新建进程时,我们需要分配新的进程描述符,并且分配新的地址空间(和父地址空间的映射保持一致,但是两者同时进入COW状态)。这些过程需要一定的开销。

进程状态

忽略去linux内核复杂的状态转移表,我们实际上可以把进程状态归结为三个最主要的状态:就绪态,运行态,睡眠态。这就是任何一本系统书上都有的三态转换图。

就绪和执行可以互相转换,基本这就是调度的过程。而当执行态程序需要等待某些条件(最典型就是IO)时,就会陷入睡眠态。而条件达成后,一般会自动进入就绪。

阻塞

当进程需要在某个文件句柄上做IO,这个fd又没有数据给他的时候,就会发生阻塞。具体来说,就是记录XX进程阻塞在了XX fd上,然后将进程标记为睡眠态,并调度出去。当fd上有数据时(例如对端发送的数据到达),就会唤醒阻塞在fd上的进程。进程会随后进入就绪队列,等待合适的时间被调度。

阻塞后的唤醒也是一个很有意思的话题。当多个上下文阻塞在一个fd上(虽然不多见,但是后面可以看到一个例子),而且fd就绪时,应该唤醒多少个上下文呢?传统上应当唤醒所有上下文,因为如果仅唤醒一个,而这个上下文又不能消费所有数据时,就会使得其他上下文处于无谓的死锁中。

但是有个著名的例子——accept,也是使用读就绪来表示收到的。如果试图用多个线程来accept会发生什么?当有新连接时,所有上下文都会就绪,但是只有第一个可以实际获得fd,其他的被调度后又立刻阻塞。这就是惊群问题thundering herd problem。

现代linux内核已经解决了这个问题,方法惊人的简单——accept方法加锁。

(inet_connection_sock.c:inet_csk_wait_for_connect)

线程

线程是一种轻量进程,实际上在linux内核中,两者几乎没有差别,除了一点——线程并不产生新的地址空间和资源描述符表,而是复用父进程的。
但是无论如何,线程的调度和进程一样,必须陷入内核态。

二、传统网络服务模型

进程模型

为每个客户分配一个进程。优点是业务隔离,在一个进程中出现的错误不至于影响整个系统,甚至其他进程。Oracle传统上就是进程模型。缺点是进程的分配和释放有非常高的成本。因此Oracle需要连接池来保持连接减少新建和释放,同时尽量复用连接而不是随意的新建连接。

线程模型

为每客户分配一个线程。优点是更轻量,建立和释放速度更快,而且多个上下文间的通讯速度非常快。缺点是一个线程出现问题容易将整个系统搞崩溃。

一个例子

py_http_fork_thread.py

在这个例子中,线程模式和进程模式可以轻易的互换。

如何工作的:

  1. 父进程监听服务端口
  2. 在有新连接建立的时候,父进程执行fork,产生一个子进程副本
  3. 如果子进程需要的话,可以exec(例如CGI)
  4. 父进程执行(理论上应当先执行子进程,因为exec执行的快可以避免COW)到accept后,发生阻塞
  5. 上下文调度,内核调度器选择下一个上下文,如无意外,应当就是刚刚派生的子进程
  6. 子进程进程进入读取处理状态,阻塞在read调用上,所有上下文均进入睡眠态
  7. 随着SYN或者数据报文到来,CPU会唤醒对应fd上阻塞的上下文(wait_que
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值