攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第5天,點擊查看活動詳情
這裡主要使用的就是asyncio
這個庫,Is used to write concurrent code,使用 async/await 語法,As for coroutines and asynchronous to do,You can refer to the official documentation of a paragraph:
協程是子例程的更一般形式.子例程可以在某一點進入並在另一點退出. 協程則可以在許多不同的點上進入、退出和恢復. 它們可通過 async def 語句來實現
Asynchronous applications running on different python Version there are different ways,If you look at the following online this method of running asynchronous applications:
import asyncio
async def hello_world():
print("Hello World!")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello_world())
loop.close()
復制代碼
Write is right,But this method is python3.7 Before running asynchronous method,在 3.7 After a more simple writing,如下:
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
復制代碼
Also recommends using more advanced writing,Because who wouldn't want to write less code.
在 python 中,If you want to directly call a useasync
Decoration of the asynchronous function,A little to be in the front andawait
等待運行結束
When you want to create a background task,Make it slowly,可以用這個:asyncio.create_task(coro, *, name=None)
其中 name 形參是 3.8 加入進去的,Meaning is the name of the task,使用實例如下:
import asyncio
async def task():
await asyncio.sleep(3)
print("任務執行完畢")
async def factorial(name, number):
f = 1
await asyncio.sleep(1)
f *= number
print(f"Task {name}: factorial({number}) = {f}")
return f
async def main():
asyncio.create_task(task())
await factorial("A", 1)
await factorial("B", 1)
await factorial("C", 1)
if __name__ == '__main__':
asyncio.run(main())
# 運行結果:
Task A: factorial(1) = 1
Task B: factorial(1) = 1
任務執行完畢
Task C: factorial(1) = 1
復制代碼
You can see we created in the beginning a background tasktask
,該任務會在 3 Seconds after the output content,Then call the function three timesfactorial
,This function will wait 1 秒後返回,So the output the following,But if you try to put the functionfactorial
只運行 1 This or two,會發現任務task
Not the execution of the program is over,Because we just treat it as a background task to run,並沒有等待,這時有兩種方案:
import asyncio
async def task():
await asyncio.sleep(3)
print("任務執行完畢")
async def factorial(name, number):
f = 1
await asyncio.sleep(1)
f *= number
print(f"Task {name}: factorial({number}) = {f}")
return f
async def main():
t = asyncio.create_task(task())
await factorial("A", 1)
await t
if __name__ == '__main__':
asyncio.run(main())
# 運行結果
Task A: factorial(1) = 1
任務執行完畢
復制代碼
See the above you might say,我懂了,As long as the batch create tasks,It is not the concurrent?也沒錯,但有更好的方法,就是使用asyncio.gather(*aws, return_exceptions=False)
,有兩個參數,The first parameter is a pile of coroutines,The second is when an exception occurs is directly interrupt or as the result returned together,The default is not interrupt return,這個函數有一個返回值,That is all the tasks the running result of the,如下示例:
import asyncio
async def factorial(name, number):
f = 1
await asyncio.sleep(1)
f *= number
print(f"Task {name}: factorial({number}) = {f}")
return f
async def main():
results = await asyncio.gather(
factorial("A", 2),
factorial("B", 3),
factorial("C", 4),
)
print(results)
if __name__ == '__main__':
asyncio.run(main())
# 運行結果
Task A: factorial(2) = 2
Task B: factorial(3) = 3
Task C: factorial(4) = 4
[2, 3, 4]
復制代碼
到現在為止,Have completed using asynchronous concurrent operation,But this kind of concurrency is uncontrollable,Such as thread pool and processes handled in the pool,都有一個參數為max_workers
,Is to control the speed with,In asynchronous programming has control concurrent speed,叫做信號量
,Simple to write a sample:
import asyncio
import string
async def factorial(name, number, sem):
async with sem:
f = 1
await asyncio.sleep(1)
f *= number
print(f"Task {name}: factorial({number}) = {f}")
return f
async def main():
sem = asyncio.Semaphore(5)
func_list = [factorial(char, index, sem) for index, char in enumerate(string.ascii_uppercase)]
results = await asyncio.gather(*func_list)
print(results)
if __name__ == '__main__':
asyncio.run(main())
# 運行結果
Task A: factorial(0) = 0
Task C: factorial(2) = 2
Task E: factorial(4) = 4
Task B: factorial(1) = 1
Task D: factorial(3) = 3
Task F: factorial(5) = 5
Task H: factorial(7) = 7
Task J: factorial(9) = 9
Task G: factorial(6) = 6
Task I: factorial(8) = 8
Task K: factorial(10) = 10
Task M: factorial(12) = 12
Task O: factorial(14) = 14
Task L: factorial(11) = 11
Task N: factorial(13) = 13
Task P: factorial(15) = 15
Task R: factorial(17) = 17
Task T: factorial(19) = 19
Task Q: factorial(16) = 16
Task S: factorial(18) = 18
Task U: factorial(20) = 20
Task W: factorial(22) = 22
Task Y: factorial(24) = 24
Task V: factorial(21) = 21
Task X: factorial(23) = 23
Task Z: factorial(25) = 25
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
復制代碼
Look at the output of time you will find5個5A set of output out,This is used to signal:asyncio.Semaphore()
,He has only one parameter is to limit the number of concurrent,Then to limit the code using context manager wrapped it would be nice,但要注意的是,To instantiate a semaphore in the main event loop,也就是使用async
Decorative function can only be inside,否則會報錯,大家可以嘗試一下.
In fact, on the title“Parallel programming practice is not serious”,Because of the thread pools and asynchronous coroutines are belong to the concurrent,Only is the parallel multi-process.然後呢,This article also just take you into the door,Know how to use.As for why didn't write so detailed?I want to see more of you,Just regard it as an introduction to,Then by myself to learn more in-depth knowledge.