多进程 (Process)
os.fork() # 子进程返回0,父进程返回子进程id
os.getpid() # 返回进程id
os.getppid() # 返回父进程id
Unix/Linux上的多进程
常见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。
import os
print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
Process (876) start...
I (876) just created a child process (877).
I am child process (877) and my parent is 876.
Windows上的多进程
multiprocessing模块提供了一个Process类来代表一个进程对象
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
Parent process 928.
Child process will start.
Run child process test (929)...
Process end.
多线程 (Thread)
协程 (Coroutine)
asyncio
用asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from调用另一个coroutine实现异步操作。
asyncawait
为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async和await,可以让coroutine的代码更简洁易读。
请注意,async和await是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
- 把@asyncio.coroutine替换为async;
- 把yield from替换为await。
aiohttp
asyncio实现了TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架。五种I/O
参考:https://www.cyc2018.xyz/计算机基础/Socket/Socket.html阻塞式I/O
一次I/O就需要一个线程来处理。
在发出一个调用时,在没有得到结果之前, 该调用就不返回。此时程序被阻塞(blocking),处于等待(waiting)状态。非阻塞式I/O(进程自己轮询I/O是否完成,效率低)
I/O 复用(select、poll,其实也是阻塞式,但是可以处理多个IO)
让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。
使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。信号驱动I/O
异步I/O
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
前面四种都是同步IO,因为从kernel复制数据到user时线程都会被阻塞,必须等copy完成线程才能继续执行。IO复用
select
参数:关注的socket描述符,每个描述符的状态(读、写),等待时间。poll
epoll