背景
python 并发最强大的地方 就是使用协程。 tornado 基于事件循环, 轮询的方式来实现并发, 在阅读本篇文章的时候 默认为你有了一定的 基础知识, 使用过yield yield from async await 并充分理解了。 django 每创建一个连接就会创建一个线程, 这样对服务器的要求比较高, 服务器的压力比较大。 tornado 充分利用协程实现并发, 使用各种异步库来实现并发。 但是还有很多没有优秀的异步库, 或者说是不稳定。 例如mysql 目前没有敢用的 异步操作mysql的库。 现在最好的办法就是 将这样的阻塞函数 通过一定的方法给转化为非阻塞的。
一、在for 循环中使用
比如下载的时候网络IO流 是阻塞的 一种方法是变为非阻塞的, 一种方法是使用异步访问库。
直接将方法变为非阻塞的函数
from concurrent import futures
from flags import save_flag, get_flag, show, main
MAX_WORKERS = 20
def download_one(cc):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower() + '.gif')
return cc
def download_many(cc_list):
workers = min(MAX_WORKERS, len(cc_list))
with futures.ThreadPoolExecutor(workers) as executor:
res = executor.map(download_one, sorted(cc_list))
return len(list(res))
if __name__ == '__main__':
main(download_many)
以上是伪代码,内部使用的是多线程。使用map过后 能直接得到结果, 是一个生成器。 要获取到具体的值要调用迭代器, 进行循环获取。 map的优点是 能够保证顺序, 按照进去的顺序出来 res 的值。 确定是, 等到所有的任务排定完再执行 任务。 这样不能达到最快, 拆分的话 不能保证顺序但是 是当任务出来之后就会执行。 用比较官网的说法。
map 方法的作用与内置的map函数类型类似, 不过download_one 函数会在多个线程中并发调用; map 方法返回一个生成器, 因此可以迭代,, 获取各个函数返回的值。
注意: 编写并发代码时候经常这样重构: 把依次for 循环体改成函数, 以便这样并发调用。
为了了解future (期物) 现在来慢慢介绍下
我们目前用的库是concurrent.futures
标准库中有两个名为Future 的类: concurrent.futures.Future 和asyncio.Future. 两个类的作用相同:两个类都表示可能已经完成或