程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python Parallel Programming Practice (Part 2)

編輯:Python

攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第5天,點擊查看活動詳情

Python 並行編程實踐(下)

協程與異步

這裡主要使用的就是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 useasyncDecoration 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,會發現任務taskNot the execution of the program is over,Because we just treat it as a background task to run,並沒有等待,這時有兩種方案:

  • If your application server program need not tube,Anyway, will not end
  • If your code is a script can be in finally wait for the end of the background 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():
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,也就是使用asyncDecorative 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.


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved