Python异步编程:asyncio库的使用说明,以及和multiprocessing 的性能对比(2分钟立马掌握)

关于同步和异步的理解:

当我执行一段程序时,不仅需要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 后面的对象必须是如下格式之一

  1. 原生 coroutine 对象
  2. 一个由 types.coroutine() 修饰的生成器,这个生成器可以返回 coroutine 对象。
  3. 一个包含 __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

 

### 回答1: `multiprocessing.pool.Pool` 是 Python 中的一个多进程管理工具,可以帮助我们实现多进程并行计算。下面是一个简单的使用方法: 1. 创建进程池: ``` from multiprocessing import Pool # 创建进程池,并指定最大进程数 p = Pool(processes=4) ``` 2. 定义任务函数: ``` def task(data): # 在这里实现具体的任务逻辑 result = data * 2 return result ``` 3. 使用进程池进行任务分配: ``` # 向进程池分配任务 result_list = p.map(task, [1, 2, 3, 4, 5]) # 输出结果 print(result_list) ``` 完整的代码示例: ``` from multiprocessing import Pool def task(data): result = data * 2 return result if __name__ == '__main__': p = Pool(processes=4) result_list = p.map(task, [1, 2, 3, 4, 5]) print(result_list) ``` ### 回答2multiprocessing.pool.Pool是Python中内置的一个用于进程池管理的模块。通过使用Pool对象,可以方便地开启多个进程,并且可以控制进程的数量任务的分配。 要使用multiprocessing.pool.Pool,首先需要先导入相关的模块,使用方法如下: ```python import multiprocessing from multiprocessing import Pool ``` 然后可以创建一个Pool对象,指定进程的数量,一般推荐使用计算机的CPU核心数量作为进程的数量,这样可以充分利用计算资源: ```python pool = Pool(multiprocessing.cpu_count()) ``` 接下来,可以通过Pool对象的map()方法来进行任务的分配执行。map()方法接收两个参数,第一个参数是函数,第二个参数是函数的输入数据(一般为一个可迭代对象)。这里要注意的是,被调用的函数必须是可pickle的,也就是说它必须在一个模块的顶层定义,不能在类或者函数定义中: ```python results = pool.map(func, iterable) ``` 另外一个常用的方法是apply_async(),可以异步执行多个函数,这个函数可以接收多个参数,使用方式如下: ```python result = pool.apply_async(func, args=(arg1, arg2, ...)) ``` 最后,使用完Pool对象后,要记得关闭并销毁Pool对象,释放相关的资源,可以通过close()join()方法来完成: ```python pool.close() pool.join() ``` 上面介绍的是multiprocessing.pool.Pool的一些基本使用方法,通过使用Pool对象,可以方便地实现并发执行任务,提高程序的运行效率。 ### 回答3: `multiprocessing.pool.Pool`是Python中的一个多进程模块,可以用于进行并行计算。它提供了一种简单而实用的方式来创建进程池,从而可以并行地执行多个任务。 首先,我们需要导入`multiprocessing.pool`模块: ```python import multiprocessing from multiprocessing import pool ``` 然后,我们可以使用以下方法来创建进程池对象: ```python p = multiprocessing.pool.Pool(processes=None) ``` 其中,`processes`参数用于指定进程池中的进程数量。如果不指定该参数,则默认为CPU的核心数量。 接下来,我们可以使用进程池对象的`apply`方法来执行一些函数或者方法: ```python result = p.apply(func, args=(), kwds={}) ``` 其中,`func`是要执行的函数或方法,`args`是要传递给函数或方法的位置参数,`kwds`是要传递给函数或方法的关键字参数。 此外,我们还可以使用进程池对象的`map`方法来同时对多个参数进行函数调用: ```python results = p.map(func, iterable, chunksize=None) ``` 其中,`func`是要执行的函数,`iterable`是一个可迭代对象,`chunksize`用于指定每个进程一次处理的数据量。 最后,记得在程序结束后关闭进程池对象: ```python p.close() p.join() ``` 这样可以确保所有的子进程都已经终止。 综上所述,`multiprocessing.pool.Pool`可以帮助我们实现多进程的并行计算,提高程序的运行效率。通过使用`apply``map`方法,我们可以轻松地执行函数或方法,并获得它们的结果。同时,我们需要记得在程序结束后关闭进程池对象,以防止资源泄漏。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值