关于同步和异步的理解:
当我执行一段程序时,不仅需要CPU处理,还需要硬盘、网络等IO操作。而事实是,CPU的速度远大于IO操作速度。
假设:此时有个程序的过程是,CPU处理--IO操作--CPU处理,进过三次操作才能完成。但是在进行IO操作时,程序就卡住了(因为太慢了)。
如果你写程序的逻辑是:先完成整个的------CPU处理--IO操作--CPU处理,才能进行下一个进程,那么,你的程序就是同步的。
如果你写程序的逻辑是:第一个线程先完成CPU处理,传递给IO操作,此时虽然卡住了,但是可以进行第二个线程再次从CPU处理开始。等第一个IO操作完成后,再交给CPU处理。第二个IO操作完成后,再交给CPU处理。这样你的程序就是异步的。
代码实现和对比
我们用几种不同的方式来运行---打印20个时间戳。
第一轮:同步的方式(我们刚学编程时,普遍的思维方式):即打印一个时间戳后停顿1秒。
import time
def hello():
time.sleep(1)
def run():
for i in range(10):
hello()
print('Hello World:%s' % time.time())
if __name__ == '__main__':
run()
可以看到输出如下:确实是间隔一秒后输出结果。前后十个线程间隔为:9秒
第二轮:异步的方式,用到 multiprocessing 库:这也是个异步的库。
import time
from multiprocessing.pool import Pool
def hello():
time.sleep(1)
def run(i):
hello()
print('Hello World:%s' % time.time())
if __name__ == '__main__':
pool = Pool()
pool.map(run,[i for i in range(10)])
最终可以看到输出结果,前后十个进程间隔为:0.107秒
第三轮:异步的方式。使用asyncio库。
import time
import asyncio
# 这是定义异步函数,先记住写法即可
async def hello():
asyncio.sleep(1)
print('Hello World:%s' % time.time())
def run():
for i in range(10):
loop.run_until_complete(hello()) # 这是让这个事件一直处理下去,直到结束后再提交给下一步、进行该线程的剩余操作。
loop = asyncio.get_event_loop() # 这是创建一个事件循环,可以理解为类中的,实例化的概念
if __name__ == '__main__':
run()
最后的结果如下,前后十个线程的间隔为:0.001 秒
总结:
从以上测试可以看到同步和异步在性能上的差别还是很大的,如果程序更复杂,他们之间的差异会更大。
至于异步常用的库 multiprocessing 和asyncio 间,后者效率更高些,具体的差异细节,大家可以做更深入的测试进行调试。
基本的会用到的代码部分有:
async def get(i):
print('1start',i)
await asyncio.sleep(2)
print('2start',i)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
tasks = []
for i in range(5):
tasks.append(asyncio.ensure_future(get(i)))
print(tasks)
# tasks = [asyncio.ensure_future(get('1')),asyncio.ensure_future(get('2'))]
loop.run_until_complete(asyncio.wait(tasks))
注意,有时,这个wait +do_someting() 会报错,如:
TypeError: object Response can't be used in 'await' expression
这个错误的意思是 requests 返回的 Response 对象不能和 await 一起使用,await 后面的对象必须是如下格式之一
- 原生 coroutine 对象
- 一个由 types.coroutine() 修饰的生成器,这个生成器可以返回 coroutine 对象。
- 一个包含 __await 方法的对象返回的一个迭代器。
reqeusts 返回的 Response 不符合上面任一条件,因此就会报上面的错误了。
既然 await
后面的对象要是 coroutine
对象 ,那么将其包装在async
后面不就可以了吗?
async def delete_one(product):
stat = time.time()
await asyncio.sleep(3)
await do_delete(product)
print('这里用时',time.time()-stat)
async def do_delete(product):
client = pymongo.MongoClient('mongodb://root:1111111@11111111111111:27017')
db = client['traffic']
db_next_day_data = db['next_day_data']
return db_next_day_data.delete_one(product)
def delete_finish_data(result):
tasks = []
for i in result:
departureAirport = i.get('departureAirport')
arrivalAirport = i.get('arrivalAirport')
flightDate = i.get('flightDate')
flightNo = i.get('flightNo')
product = {
"flightNo": flightNo,
"departureAirport": departureAirport,
"arrivalAirport": arrivalAirport,
"flightDate": flightDate,
}
tasks.append(asyncio.ensure_future(delete_one(product)))
start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print('完成删除',time.time()-start)
更多的asyncio的使用场景,可以参考以下这篇说明:
http://www.sohu.com/a/302896961_571478