欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python快速實現(xiàn)一個線程池的示例代碼

 更新時間:2022年07月20日 09:31:54   作者:古明地覺  
當有多個?IO?密集型的任務要被處理時,我們自然而然會想到多線程。而線程池的實現(xiàn)也很簡單,因為?Python?提供了一個標準庫?concurrent.futures,已經(jīng)內(nèi)置了對線程池的支持。所以本篇文章,我們就來詳細介紹一下該模塊的用法

楔子

當有多個 IO 密集型的任務要被處理時,我們自然而然會想到多線程。但如果任務非常多,我們不可能每一個任務都啟動一個線程去處理,這個時候最好的辦法就是實現(xiàn)一個線程池,至于池子里面的線程數(shù)量可以根據(jù)業(yè)務場景進行設置。

比如我們實現(xiàn)一個有 10 個線程的線程池,這樣可以并發(fā)地處理 10 個任務,每個線程將任務執(zhí)行完之后,便去執(zhí)行下一個任務。通過使用線程池,可以避免因線程創(chuàng)建過多而導致資源耗盡,而且任務在執(zhí)行時的生命周期也可以很好地把控。

而線程池的實現(xiàn)方式也很簡單,但這里我們不打算手動實現(xiàn),因為 Python 提供了一個標準庫 concurrent.futures,已經(jīng)內(nèi)置了對線程池的支持。所以本篇文章,我們就來詳細介紹一下該模塊的用法。

Future 對象

當我們往線程池里面提交一個函數(shù)時,會分配一個線程去執(zhí)行,同時立即返回一個 Future 對象。通過 Future 對象可以監(jiān)控函數(shù)的執(zhí)行狀態(tài),有沒有出現(xiàn)異常,以及有沒有執(zhí)行完畢等等。如果函數(shù)執(zhí)行完畢,內(nèi)部便會調(diào)用 future.set_result 將返回值設置到 future 里面,然后外界便可調(diào)用 future.result 拿到返回值。

除此之外 future 還可以綁定回調(diào),一旦函數(shù)執(zhí)行完畢,就會以 future 為參數(shù),自動觸發(fā)回調(diào)。所以 future 被稱為未來對象,可以把它理解為函數(shù)的一個容器,當我們往線程池提交一個函數(shù)時,會立即創(chuàng)建相應的 future 然后返回。函數(shù)的執(zhí)行狀態(tài)什么的,都通過 future 來查看,當然也可以給它綁定一個回調(diào),在函數(shù)執(zhí)行完畢時自動觸發(fā)。

那么下面我們就來看一下 future 的用法,文字的話理解起來可能有點枯燥。

"""
將函數(shù)提交到線程池里面運行時,會立即返回一個對象
這個對象就叫做?Future?對象,里面包含了函數(shù)的執(zhí)行狀態(tài)等等
當然我們也可以手動創(chuàng)建一個Future對象。
"""
from?concurrent.futures?import?Future

#?創(chuàng)建?Future?對象?future
future?=?Future()

#?給?future?綁定回調(diào)
def?callback(f:?Future):
????print("當set_result的時候會執(zhí)行回調(diào),result:",
??????????f.result())

future.add_done_callback(callback)
#?通過?add_done_callback?方法即可給?future?綁定回調(diào)
#?調(diào)用的時候會自動將?future?作為參數(shù)
#?如果需要多個參數(shù),那么就使用偏函數(shù)

#?回調(diào)函數(shù)什么時候執(zhí)行呢?
#?顯然是當?future?執(zhí)行?set_result?的時候
#?如果?future?是向線程池提交函數(shù)時返回的
#?那么當函數(shù)執(zhí)行完畢時會自動執(zhí)行?future.set_result(xx)
#?并將自身的返回設置進去
#?而這里的?future?是我們手動創(chuàng)建的,因此需要手動執(zhí)行
future.set_result("嘿嘿")
"""
當set_result的時候會執(zhí)行回調(diào),result:?嘿嘿
"""

需要注意的是:只能執(zhí)行一次 set_result,但是可以多次調(diào)用 result 獲取結(jié)果。

from?concurrent.futures?import?Future

future?=?Future()
future.set_result("哼哼")

print(future.result())??#?哼哼
print(future.result())??#?哼哼
print(future.result())??#?哼哼

執(zhí)行 future.result() 之前一定要先 set_result,否則會一直處于阻塞狀態(tài)。當然 result 方法還可以接收一個 timeout 參數(shù),表示超時時間,如果在指定時間內(nèi)沒有獲取到值就會拋出異常。

提交函數(shù)自動創(chuàng)建 Future 對象

我們上面是手動創(chuàng)建的 Future 對象,但工作中很少會手動創(chuàng)建。我們將函數(shù)提交到線程池里面運行的時候,會自動創(chuàng)建 Future 對象并返回。這個 Future 對象里面就包含了函數(shù)的執(zhí)行狀態(tài),比如此時是處于暫停、運行中還是完成等等,并且函數(shù)在執(zhí)行完畢之后,還會調(diào)用 future.set_result 將自身的返回值設置進去。

from?concurrent.futures?import?ThreadPoolExecutor
import?time

def?task(name,?n):
????time.sleep(n)
????return?f"{name}?睡了?{n}?秒"

#?創(chuàng)建一個線程池
#?里面還可以指定?max_workers?參數(shù),表示最多創(chuàng)建多少個線程
#?如果不指定,那么每提交一個函數(shù),都會為其創(chuàng)建一個線程
executor?=?ThreadPoolExecutor()

#?通過?submit?即可將函數(shù)提交到線程池,一旦提交,就會立刻運行
#?因為開啟了一個新的線程,主線程會繼續(xù)往下執(zhí)行
#?至于?submit?的參數(shù),按照函數(shù)名,對應參數(shù)提交即可
#?切記不可寫成task("古明地覺",?3),這樣就變成調(diào)用了
future?=?executor.submit(task,?"古明地覺",?3)

#?由于函數(shù)里面出現(xiàn)了?time.sleep,并且指定的?n?是?3
#?所以函數(shù)內(nèi)部會休眠?3?秒,顯然此時處于運行狀態(tài)
print(future)
"""
<Future?at?0x7fbf701726d0?state=running>
"""

#?我們說?future?相當于一個容器,包含了內(nèi)部函數(shù)的執(zhí)行狀態(tài)
#?函數(shù)是否正在運行中
print(future.running())
"""
True
"""
#?函數(shù)是否執(zhí)行完畢
print(future.done())
"""
False
"""

#?主程序也?sleep?3?秒
time.sleep(3)

#?顯然此時函數(shù)已經(jīng)執(zhí)行完畢了
#?并且打印結(jié)果還告訴我們返回值類型是?str
print(future)
"""
<Future?at?0x7fbf701726d0?state=finished?returned?str>
"""

print(future.running())
"""
False
"""
print(future.done())
"""
True
"""

#?函數(shù)執(zhí)行完畢時,會將返回值設置在?future?里
#?也就是說一旦執(zhí)行了?future.set_result
#?那么就表示函數(shù)執(zhí)行完畢了,然后外界可以調(diào)用?result?拿到返回值
print(future.result())
"""
古明地覺?睡了?3?秒
"""

這里再強調(diào)一下 future.result(),這一步是會阻塞的,舉個例子:

#?提交函數(shù)
future?=?executor.submit(task,?"古明地覺",?3)
start?=?time.perf_counter()
future.result()
end?=?time.perf_counter()
print(end?-?start)??#?3.00331525

可以看到,future.result() 這一步花了將近 3s。其實也不難理解,future.result() 是干嘛的?就是為了獲取函數(shù)的返回值,可函數(shù)都還沒有執(zhí)行完畢,它又從哪里獲取呢?所以只能先等待函數(shù)執(zhí)行完畢,將返回值通過 set_result 設置到 future 里面之后,外界才能調(diào)用 future.result() 獲取到值。

如果不想一直等待的話,那么在獲取值的時候可以傳入一個超時時間。

from?concurrent.futures?import?(
????ThreadPoolExecutor,
????TimeoutError
)
import?time

def?task(name,?n):
????time.sleep(n)
????return?f"{name}?睡了?{n}?秒"

executor?=?ThreadPoolExecutor()
future?=?executor.submit(task,?"古明地覺",?3)
try:
????#?1?秒之內(nèi)獲取不到值,拋出?TimeoutError
????res?=?future.result(1)
except?TimeoutError:
????pass

#?再?sleep?2?秒,顯然函數(shù)執(zhí)行完畢了
time.sleep(2)
#?獲取返回值
print(future.result())
"""
古明地覺?睡了?3?秒
"""

當然啦,這么做其實還不夠智能,因為我們不知道函數(shù)什么時候執(zhí)行完畢。所以最好的辦法還是綁定一個回調(diào),當函數(shù)執(zhí)行完畢時,自動觸發(fā)回調(diào)。

from?concurrent.futures?import?ThreadPoolExecutor
import?time

def?task(name,?n):
????time.sleep(n)
????return?f"{name}?睡了?{n}?秒"

def?callback(f):
????print(f.result())

executor?=?ThreadPoolExecutor()
future?=?executor.submit(task,?"古明地覺",?3)
#?綁定回調(diào),3?秒之后自動調(diào)用
future.add_done_callback(callback)
"""
古明地覺?睡了?3?秒
"""

需要注意的是,在調(diào)用 submit 方法之后,提交到線程池的函數(shù)就已經(jīng)開始執(zhí)行了。而不管函數(shù)有沒有執(zhí)行完畢,我們都可以給對應的 future 綁定回調(diào)。

如果函數(shù)完成之前添加回調(diào),那么會在函數(shù)完成后觸發(fā)回調(diào)。如果函數(shù)完成之后添加回調(diào),由于函數(shù)已經(jīng)完成,代表此時的 future 已經(jīng)有值了,或者說已經(jīng) set_result 了,那么會立即觸發(fā)回調(diào)。

future.set_result 到底干了什么事情

當函數(shù)執(zhí)行完畢之后,會執(zhí)行 set_result,那么這個方法到底干了什么事情呢?

我們看到 future 有兩個被保護的屬性,分別是 _result 和 _state。顯然 _result 用于保存函數(shù)的返回值,而 future.result() 本質(zhì)上也是返回 _result 屬性的值。而 _state 屬性則用于表示函數(shù)的執(zhí)行狀態(tài),初始為 PENDING,執(zhí)行中為 RUNING,執(zhí)行完畢時被設置為 FINISHED。

調(diào)用 future.result() 的時候,會判斷 _state 的屬性,如果還在執(zhí)行中就一直等待。當 _state 為 FINISHED 的時候,就返回 _result 屬性的值。

提交多個函數(shù)

我們上面每次只提交了一個函數(shù),但其實可以提交任意多個,我們來看一下:

from?concurrent.futures?import?ThreadPoolExecutor
import?time

def?task(name,?n):
????time.sleep(n)
????return?f"{name}?睡了?{n}?秒"

executor?=?ThreadPoolExecutor()
futures?=?[executor.submit(task,?"古明地覺",?3),
???????????executor.submit(task,?"古明地覺",?4),
???????????executor.submit(task,?"古明地覺",?1)]
#?此時都處于running
print(futures)
"""
[<Future?at?0x1b5ff622550?state=running>,
?<Future?at?0x1b5ff63ca60?state=running>,?
?<Future?at?0x1b5ff63cdf0?state=running>]
"""

time.sleep(3)
#?主程序?sleep?3s?后
#?futures[0]和futures[2]處于?finished
#?futures[1]仍處于?running
print(futures)
"""
[<Future?at?0x1b5ff622550?state=running>,?
?<Future?at?0x1b5ff63ca60?state=running>,?
?<Future?at?0x1b5ff63cdf0?state=finished?returned?str>]
"""

如果是多個函數(shù),要如何拿到返回值呢?很簡單,遍歷 futures 即可。

executor?=?ThreadPoolExecutor()
futures?=?[executor.submit(task,?"古明地覺",?5),
???????????executor.submit(task,?"古明地覺",?2),
???????????executor.submit(task,?"古明地覺",?4),
???????????executor.submit(task,?"古明地覺",?3),
???????????executor.submit(task,?"古明地覺",?6)]

for?future?in?futures:
????print(future.result())
"""
古明地覺?睡了?5?秒
古明地覺?睡了?2?秒
古明地覺?睡了?4?秒
古明地覺?睡了?3?秒
古明地覺?睡了?6?秒
"""

這里面有一些值得說一說的地方,首先 futures 里面有 5 個 future,記做 future1, future2, future3, future4, future5。

當使用 for 循環(huán)遍歷的時候,實際上會依次遍歷這 5 個 future,所以返回值的順序就是我們添加的函數(shù)的順序。由于 future1 對應的函數(shù)休眠了 5s,那么必須等到 5s 后,future1 里面才會有值。

但這五個函數(shù)是并發(fā)執(zhí)行的,future2, future3, future4 由于只休眠了 2s, 4s, 3s,所以肯定會先執(zhí)行完畢,然后執(zhí)行 set_result,將返回值設置到對應的 future 里。

但 Python 的 for 循環(huán)不可能在第一次迭代還沒有結(jié)束,就去執(zhí)行第二次迭代。因為 futures 里面的幾個 future 的順序已經(jīng)一開始就被定好了,只有當?shù)谝粋€ future.result() 執(zhí)行完成之后,才會執(zhí)行第二個 future.result(),以及第三個、第四個。

因此即便后面的函數(shù)已經(jīng)執(zhí)行完畢,但由于 for 循環(huán)的順序,也只能等著,直到前面的 future.result() 執(zhí)行完畢。所以當?shù)谝粋€ future.result() 結(jié)束時,后面三個 future.result() 會立刻輸出,因為它們內(nèi)部的函數(shù)已經(jīng)執(zhí)行結(jié)束了。

而最后一個 future,由于內(nèi)部函數(shù) sleep 了 6 秒,因此要再等待 1 秒,才會打印 future.result()。

使用 map 來提交多個函數(shù)

使用 submit 提交函數(shù)會返回一個 future,并且還可以給 future 綁定一個回調(diào)。但如果不關心回調(diào)的話,那么還可以使用 map 進行提交。

executor?=?ThreadPoolExecutor()
#?map?內(nèi)部也是使用了?submit
results?=?executor.map(task,
???????????????????????["古明地覺"]?*?3,
???????????????????????[3,?1,?2])
#?并且返回的是迭代器
print(results)
"""
<generator?object?...?at?0x0000022D78EFA970>
"""

#?此時遍歷得到的是不再是?future
#?而是?future.result()
for?result?in?results:
????print(result)
"""
古明地覺?睡了?3?秒
古明地覺?睡了?1?秒
古明地覺?睡了?2?秒
"""

可以看到,當使用for循環(huán)的時候,map 執(zhí)行的邏輯和 submit 是一樣的。唯一的區(qū)別是,此時不需要再調(diào)用 result 了,因為返回的就是函數(shù)的返回值。

或者我們直接調(diào)用 list 也行。

executor?=?ThreadPoolExecutor()
results?=?executor.map(task,
???????????????????????["古明地覺"]?*?3,
???????????????????????[3,?1,?2])
print(list(results))
"""
['古明地覺?睡了?3?秒',?
?'古明地覺?睡了?1?秒',?
?'古明地覺?睡了?2?秒']
"""

results 是一個生成器,調(diào)用 list 的時候會將里面的值全部產(chǎn)出。由于 map 內(nèi)部還是使用的 submit,然后通過 future.result() 拿到返回值,而耗時最長的函數(shù)需要 3 秒,因此這一步會阻塞 3 秒。3 秒過后,會打印所有函數(shù)的返回值。

按照順序等待執(zhí)行

上面在獲取返回值的時候,是按照函數(shù)的提交順序獲取的。如果我希望哪個函數(shù)先執(zhí)行完畢,就先獲取哪個函數(shù)的返回值,該怎么做呢?

from?concurrent.futures?import?(
????ThreadPoolExecutor,
????as_completed
)
import?time

def?task(name,?n):
????time.sleep(n)
????return?f"{name}?睡了?{n}?秒"

executor?=?ThreadPoolExecutor()
futures?=?[executor.submit(task,?"古明地覺",?5),
???????????executor.submit(task,?"古明地覺",?2),
???????????executor.submit(task,?"古明地覺",?1),
???????????executor.submit(task,?"古明地覺",?3),
???????????executor.submit(task,?"古明地覺",?4)]
for?future?in?as_completed(futures):
????print(future.result())
"""
古明地覺?睡了?1?秒
古明地覺?睡了?2?秒
古明地覺?睡了?3?秒
古明地覺?睡了?4?秒
古明地覺?睡了?5?秒
"""

此時誰先完成,誰先返回。

取消一個函數(shù)的執(zhí)行

我們通過 submit 可以將函數(shù)提交到線程池中執(zhí)行,但如果我們想取消該怎么辦呢?

executor?=?ThreadPoolExecutor()
future1?=?executor.submit(task,?"古明地覺",?1)
future2?=?executor.submit(task,?"古明地覺",?2)
future3?=?executor.submit(task,?"古明地覺",?3)
#?取消函數(shù)的執(zhí)行
#?會將?future?的?_state?屬性設置為?CANCELLED
future3.cancel()
#?查看是否被取消
print(future3.cancelled())??#?False

問題來了,調(diào)用 cancelled 方法的時候,返回的是False,這是為什么?很簡單,因為函數(shù)已經(jīng)被提交到線程池里面了,函數(shù)已經(jīng)運行了。而只有在還沒有運行時,取消才會成功。

可這不矛盾了嗎?函數(shù)一旦提交就會運行,只有不運行才會取消成功,這怎么辦?還記得線程池的一個叫做 max_workers 的參數(shù)嗎?用來控制線程池內(nèi)的線程數(shù)量,我們可以將最大的線程數(shù)設置為2,那么當?shù)谌齻€函數(shù)進去的時候,就不會執(zhí)行了,而是處于暫停狀態(tài)。

executor?=?ThreadPoolExecutor(max_workers=2)
future1?=?executor.submit(task,?"古明地覺",?1)
future2?=?executor.submit(task,?"古明地覺",?2)
future3?=?executor.submit(task,?"古明地覺",?3)
#?如果池子里可以創(chuàng)建空閑線程
#?那么函數(shù)一旦提交就會運行,狀態(tài)為?RUNNING
print(future1._state)??#?RUNNING
print(future2._state)??#?RUNNING
#?但?future3?內(nèi)部的函數(shù)還沒有運行
#?因為池子里無法創(chuàng)建新的空閑線程了,所以狀態(tài)為?PENDING
print(future3._state)??#?PENDING
#?取消函數(shù)的執(zhí)行,前提是函數(shù)沒有運行
#?會將?future?的?_state?屬性設置為?CANCELLED
future3.cancel()
#?查看是否被取消
print(future3.cancelled())??#?True
print(future3._state)??#?CANCELLED

在啟動線程池的時候,肯定是需要設置容量的,不然處理幾千個函數(shù)要開啟幾千個線程嗎。另外當函數(shù)被取消了,就不可以再調(diào)用 future.result() 了,否則的話會拋出 CancelledError。

函數(shù)執(zhí)行時出現(xiàn)異常

我們前面的邏輯都是函數(shù)正常執(zhí)行的前提下,但天有不測風云,如果函數(shù)執(zhí)行時出現(xiàn)異常了該怎么辦?

from?concurrent.futures?import?ThreadPoolExecutor

def?task1():
????1?/?0

def?task2():
????pass


executor?=?ThreadPoolExecutor(max_workers=2)
future1?=?executor.submit(task1)
future2?=?executor.submit(task2)
print(future1)
print(future2)
"""
<Future?at?0x7fe3e00f9e50?state=finished?raised?ZeroDivisionError>
<Future?at?0x7fe3e00f9eb0?state=finished?returned?NoneType>
"""

#?結(jié)果顯示?task1?函數(shù)執(zhí)行出現(xiàn)異常了
#?那么這個異常要怎么獲取呢?
print(future1.exception())
print(future1.exception().__class__)
"""
division?by?zero
<class?'ZeroDivisionError'>
"""

#?如果執(zhí)行沒有出現(xiàn)異常,那么?exception?方法返回?None
print(future2.exception())??#?None

#?注意:如果函數(shù)執(zhí)行出現(xiàn)異常了
#?那么調(diào)用?result?方法會將異常拋出來
future1.result()
"""
Traceback?(most?recent?call?last):
??File?"...",?line?4,?in?task1
????1?/?0
ZeroDivisionError:?division?by?zero
"""

出現(xiàn)異常時,調(diào)用 future.set_exception 將異常設置到 future 里面,而 future 有一個 _exception 屬性,專門保存設置的異常。當調(diào)用 future.exception() 時,也會直接返回 _exception 屬性的值。

等待所有函數(shù)執(zhí)行完畢

假設我們往線程池提交了很多個函數(shù),如果希望提交的函數(shù)都執(zhí)行完畢之后,主程序才能往下執(zhí)行,該怎么辦呢?其實方案有很多:

第一種:

from?concurrent.futures?import?ThreadPoolExecutor
import?time

def?task(n):
????time.sleep(n)
????return?f"sleep?{n}"

executor?=?ThreadPoolExecutor()

future1?=?executor.submit(task,?5)
future2?=?executor.submit(task,?2)
future3?=?executor.submit(task,?4)

#?這里是不會阻塞的
print("start")
#?遍歷所有的?future,并調(diào)用其?result?方法
#?這樣就會等到所有的函數(shù)都執(zhí)行完畢之后才會往下走
for?future?in?[future1,?future2,?future3]:
????print(future.result())
print("end")
"""
start
sleep?5
sleep?2
sleep?4
end
"""

第二種:

from?concurrent.futures?import?(
????ThreadPoolExecutor,
????wait
)
import?time

def?task(n):
????time.sleep(n)
????return?f"sleep?{n}"

executor?=?ThreadPoolExecutor()

future1?=?executor.submit(task,?5)
future2?=?executor.submit(task,?2)
future3?=?executor.submit(task,?4)

#?return_when?有三個可選參數(shù)
# FIRST_COMPLETED:當任意一個任務完成或者取消
# FIRST_EXCEPTION:當任意一個任務出現(xiàn)異常
#??????????????????如果都沒出現(xiàn)異常等同于ALL_COMPLETED
# ALL_COMPLETED:所有任務都完成,默認是這個值
fs?=?wait([future1,?future2,?future3],
??????????return_when="ALL_COMPLETED")
#?此時返回的fs是DoneAndNotDoneFutures類型的namedtuple
#?里面有兩個值,一個是done,一個是not_done
print(fs.done)
"""
{<Future?at?0x1df1400?state=finished?returned?str>,?
?<Future?at?0x2f08e48?state=finished?returned?str>,?
?<Future?at?0x9f7bf60?state=finished?returned?str>}
"""

print(fs.not_done)
"""
set()
"""
for?f?in?fs.done:
????print(f.result())
"""
start
sleep?5
sleep?2
sleep?4
end
"""

第三種:

#?使用上下文管理
with?ThreadPoolExecutor()?as?executor:
????future1?=?executor.submit(task,?5)
????future2?=?executor.submit(task,?2)
????future3?=?executor.submit(task,?4)

#?所有函數(shù)執(zhí)行完畢(with語句結(jié)束)后才會往下執(zhí)行

第四種:

executor?=?ThreadPoolExecutor()

future1?=?executor.submit(task,?5)
future2?=?executor.submit(task,?2)
future3?=?executor.submit(task,?4)
#?所有函數(shù)執(zhí)行結(jié)束后,才會往下執(zhí)行
executor.shutdown()

小結(jié)

如果我們需要啟動多線程來執(zhí)行函數(shù)的話,那么不妨使用線程池。每調(diào)用一個函數(shù)就從池子里面取出一個線程,函數(shù)執(zhí)行完畢就將線程放回到池子里以便其它函數(shù)執(zhí)行。如果池子里面空了,或者說無法創(chuàng)建新的空閑線程,那么接下來的函數(shù)就只能處于等待狀態(tài)了。

最后,concurrent.futures 不僅可以用于實現(xiàn)線程池,還可以用于實現(xiàn)進程池。兩者的 API 是一樣的:

from?concurrent.futures?import?ProcessPoolExecutor
import?time

def?task(n):
????time.sleep(n)
????return?f"sleep?{n}"

executor?=?ProcessPoolExecutor()
#?Windows?上需要加上這一行
if?__name__?==?'__main__':
????future1?=?executor.submit(task,?5)
????future2?=?executor.submit(task,?2)
????future3?=?executor.submit(task,?4)
????executor.shutdown()
????print(future1.result())
????print(future2.result())
????print(future3.result())
"""
sleep?5
sleep?2
sleep?4
"""????

線程池和進程池的 API 是一致的,但工作中很少會創(chuàng)建進程池。

以上就是Python快速實現(xiàn)一個線程池的示例代碼的詳細內(nèi)容,更多關于Python線程池的資料請關注腳本之家其它相關文章!

相關文章

  • python+selenium實現(xiàn)簡歷自動刷新的示例代碼

    python+selenium實現(xiàn)簡歷自動刷新的示例代碼

    這篇文章主要介紹了python+selenium實現(xiàn)簡歷自動刷新的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-05-05
  • python如何使用raise拋出自定義異常

    python如何使用raise拋出自定義異常

    這篇文章主要介紹了python如何使用raise拋出自定義異常問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 在IIS服務器上以CGI方式運行Python腳本的教程

    在IIS服務器上以CGI方式運行Python腳本的教程

    這篇文章主要介紹了在IIS服務器上以CGI方式運行Python腳本的教程,雖然IIS的性能并不理想...需要的朋友可以參考下
    2015-04-04
  • Python?FastAPI?Sanic?Tornado?與Golang?Gin性能實戰(zhàn)對比

    Python?FastAPI?Sanic?Tornado?與Golang?Gin性能實戰(zhàn)對比

    本文將深入比較Python的FastAPI、Sanic、Tornado以及Golang的Gin框架的各種特性、性能表現(xiàn)以及適用場景,通過詳實的性能測試和實際示例代碼,將探討它們在構(gòu)建現(xiàn)代高性能應用中的優(yōu)劣勢,以便開發(fā)者根據(jù)需求做出明智的選擇
    2024-01-01
  • Python中的單行、多行、中文注釋方法

    Python中的單行、多行、中文注釋方法

    今天小編就為大家分享一篇Python中的單行、多行、中文注釋方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • python進程間通信Queue工作過程詳解

    python進程間通信Queue工作過程詳解

    這篇文章主要介紹了python進程間通信Queue工作過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 想學畫畫?python滿足你!

    想學畫畫?python滿足你!

    這篇文章主要介紹了如何利用python畫畫,幫助大家更好的理解和使用python的turtle庫,感興趣的朋友可以了解下
    2020-12-12
  • 分享10個拿來即用的Python自動化腳本

    分享10個拿來即用的Python自動化腳本

    這篇文章主要來和大家分享10個拿來即用的Python自動化腳本,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-12-12
  • 詳解mac python+selenium+Chrome 簡單案例

    詳解mac python+selenium+Chrome 簡單案例

    這篇文章主要介紹了詳解mac python+selenium+Chrome 簡單案例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • 梯度下降法介紹及利用Python實現(xiàn)的方法示例

    梯度下降法介紹及利用Python實現(xiàn)的方法示例

    梯度下降算法是一個很基本的算法,在機器學習和優(yōu)化中有著非常重要的作用,下面這篇文章主要給大家介紹了關于利用Python實現(xiàn)梯度下降法的相關資料,對大家具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-07-07

最新評論