协程和线程
迭代器
是一种可以遍历的对象,可以作用于next()函数
生成器
Python中一边循环一边计算的机制称为生成器 比如生成器函数(yield )
装饰器
可以使用装饰器,装饰该函数,在不改变原函数的情况下,增加功能
进程,线程和协程
进程在操作系统上运行的一个程序, 操作系统以进程为单位分配资源, 每个进程都有自己的地址空间、内存、数据栈以及其他用于跟踪进程执行的辅助数据, 操作系统管理所有进程的执行, 并为这些进程合理的分配资源
线程是操作系统能够进行运算调度的最小单位, 被包含在进程之中, 是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流, 一个进程中可以并发多个线程, 每条线程并行执行不同的任务
- 进程是资源(包括内存、打开的文件等)分配的单位,线程是 CPU 调度的单位
- 线程能减少并发执行的时间和空间开销
- 进程拥有一个完整的资源平台,而线程只独享必不可少的资源,如寄存器和栈
协程的作用, 是在执行函数A时, 可以随时中断, 去执行函数B, 然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句), 这一整个过程看似像多线程, 然而协程只有一个线程执行。
并发与并行
并发通常指有多个任务需要同时进行, 并行则是同一时刻有多个任务执行。用多线程、多进程、协程来说, 协程实现并发, 多线程与多进程实现并行
多线程多个任务在同一时间执行
生成器变为协程
通过yield关键字和.send方法, 用户可以随时中断一个函数执行转而执行另一个函数, 相当于手动从一个子程序的执行切换到了另一个子程序的执行。在这种子程序的切换过程中没有涉及到线程的切换, 我们将一个子程序和它被执行以及被挂起时的状态称之为一个协程
1 |
|
1 |
|
asyncio和future
future对象由asyncio创建
future表示终将发生的事情, 而确定某件事会发生的唯一方式就是执行的时间已经排定
future对象
future对象有四个状态:Pending、Running、Done、Cancelled。创建future的时候, task为pending, 事件循环调用执行的时候当然就是running, 调用完毕自然就是done, 如果需要停止事件循环, 就需要先把task取消, 可以使用asyncio.Task获取事件循环的task
asyncio协程如何实现并发
asyncio想要实现并发, 就需要多个协程来完成任务, 每当有任务阻塞的时候就await, 然后其他协程继续工作, 这需要创建多个协程的列表, 然后将这些协程注册到事件循环中。这里指的多个协程, 可以是多个协程函数, 也可以是一个协程函数的多个协程对象
处理并发
Python中处理并发与大多数语言一样, 但也有不一样的地方。常见的处理并发的方式如下:
-
使用进程池。即, 预先fork好一定数量的进程, 每来一个请求, 就从进程池中分配一个进程去处理该请求, 处理完成之后, 再将该进程放回进程池。这种方式的优点是可以充分利用多核, 但缺点同样明显, 就是比较浪费CPU, 因为多进程切换的时候由于要保存上下文, 需要更多的指令来保存更多的数据。而且进程比线程占用更多的内存。
-
使用线程池。与进程池工作原理类似, 但是每次是使用线程来处理请求。Python中使用线程池有一个比较大的缺点就是Python有GIL, 也就意味着, Python使用线程池无法充分利用多核。
-
使用协程。借助gevent这类工具, Python可以轻松的以同步的方式写出异步的代码, 从而可以轻松的处理并发问题, 同时配合使用进程池, 便可以充分利用多核, 并且借助event loop, 高效的处理I/O事件, 通常这都是Python中的最佳实践方案。