日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Python Web学习笔记之Python多线程基础

發(fā)布時(shí)間:2023/11/27 生活经验 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python Web学习笔记之Python多线程基础 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

多線程理解

多線程是多個(gè)任務(wù)同時(shí)運(yùn)行的一種方式。比如一個(gè)循環(huán)中,每個(gè)循環(huán)看做一個(gè)任務(wù),我們希望第一次循環(huán)運(yùn)行還沒結(jié)束時(shí),就可以開始第二次循環(huán),用這種方式來節(jié)省時(shí)間。

python中這種同時(shí)運(yùn)行的目的是最大化利用CPU的計(jì)算能力,將很多等待時(shí)間利用起來。這也說明如果程序耗時(shí)不是因?yàn)榈却龝r(shí)間,而是任務(wù)非常多,就是要計(jì)算那么久,則多線程無法改善運(yùn)行時(shí)間。

更多有關(guān)多線程理解的內(nèi)容可以參考下面資料

  • 廖雪峰教程
  • 知乎回答
  • 百度一下還有非常多的說明,這里不再贅述

?

簡(jiǎn)單使用

先看下面這個(gè)函數(shù)

import time
def myfun():time.sleep(1)a = 1 + 1print(a)

如果我們要運(yùn)行10次這個(gè)函數(shù),它的運(yùn)行時(shí)間主要在于每次sleep的那一秒,1 + 1的計(jì)算是不會(huì)耗多少時(shí)間的。這種情況可以用多線程提高效率。

下面來看一下不使用多線程耗時(shí)和使用多線程的耗時(shí)

不使用多線程

t = time.time()
for _ in range(5):myfun()
print(time.time() - t)

得到結(jié)果是 5.002434492111206

下面我們使用多線程

from threading import Thread
for _ in range(5):th = Thread(target = myfun)th.start()

這樣使用多線程其實(shí)就可以了,你會(huì)發(fā)現(xiàn)大概1秒,5個(gè)2會(huì)同時(shí)出來,說明5次循環(huán)其實(shí)幾乎同時(shí)運(yùn)行,5次1秒的等待時(shí)間同時(shí)進(jìn)行,最后只等待了1秒。

這里多線程只包括了兩步

  • Thread增加一個(gè)線程,這里是將每一次循環(huán)作為一次新的線程,一個(gè)線程執(zhí)行一次myfun函數(shù)。
  • start()開始運(yùn)行這個(gè)線程,每個(gè)線程都需要這樣顯式開啟才會(huì)運(yùn)行。一個(gè)線程這樣開啟后,不需要等待它運(yùn)行完成,就可以繼續(xù)運(yùn)行下面的程序,即下一次循環(huán)(然后又新建了第二個(gè)線程,運(yùn)行未結(jié)束即開啟第三個(gè)……)

這里要注意一點(diǎn):多線程是放在循環(huán)里面的,不能定義好循環(huán)之后,從外面將它變成多線程。

讀者可能會(huì)注意到,不用多線程時(shí)是通過程序計(jì)算時(shí)間的,使用多線程卻沒有。這是因?yàn)橐?jì)算時(shí)間需要增加一些代碼,無法展示最簡(jiǎn)單的多線程使用,所以就先不計(jì)算時(shí)間。接下來我們就講join()的使用,并計(jì)算時(shí)間。

join的使用

線程的join()方法表示等這個(gè)線程運(yùn)行完畢,程序再往下運(yùn)行。我們來看下面的例子

from threading import Thread
t = time.time()
for _ in range(5):th = Thread(target = myfun)th.start()th.join()
print(time.time() - t)
# 結(jié)果為 5.0047078132629395 秒

這里start()之后馬上join(),表示每一個(gè)線程都要運(yùn)行結(jié)束才能進(jìn)行下一次循環(huán),這樣就和沒有使用多線程沒有區(qū)別了。不過如果要計(jì)算多線程運(yùn)行時(shí)間卻是要用到這個(gè)join()

我們先看一下不用join()的情況

from threading import Thread
t = time.time()
for _ in range(5):th = Thread(target = myfun)th.start()
print(time.time() - t)
# 結(jié)果為  0.0009980201721191406 秒

它連1秒都沒有等,就輸出了結(jié)果,而且5個(gè)2是在打印出這個(gè)之后才輸出出來的。這是因?yàn)?code>print(time.time() - t)是區(qū)別于那5次循環(huán)線程之外的第6個(gè)線程,它不會(huì)等待5個(gè)線程運(yùn)行結(jié)束就會(huì)開始運(yùn)行。所以這樣是無法獲得上面5個(gè)線程的運(yùn)行時(shí)間的,我們需要用join()等待5個(gè)線程都運(yùn)行結(jié)束。

代碼如下

from threading import Thread
t = time.time()
ths = []
for _ in range(5):th = Thread(target = myfun)th.start()ths.append(th)
for th in ths:th.join()
print(time.time() - t)
# 結(jié)果為 1.0038363933563232

上面定義ths列表存儲(chǔ)這些線程,最后用循環(huán)確保每一個(gè)線程都已經(jīng)運(yùn)行完成再計(jì)算時(shí)間差。

join()不只是用于這種情形。當(dāng)一步代碼運(yùn)行依賴之前代碼運(yùn)行完成時(shí),就要加入join()命令。

現(xiàn)在我們已經(jīng)學(xué)完了多線程的一般使用方法,可以在多數(shù)場(chǎng)景使用了。下面來介紹一些細(xì)節(jié)

其他

(1)線程名稱

我們直接看下面的代碼

import threading
print(threading.current_thread().getName())
def myfun():time.sleep(1)print(threading.current_thread().name)a = 1 + 1
for i in range(5):th = threading.Thread(target = myfun, name = 'thread {}'.format(i))th.start()
# 輸出結(jié)果
MainThread
thread 0
thread 1
thread 4
thread 3
thread 2

解釋一下

  • threading.current_thread()表示當(dāng)前線程,可以調(diào)用namegetName()獲取線程名稱
  • 任何進(jìn)程都會(huì)默認(rèn)啟動(dòng)一個(gè)線程,默認(rèn)名稱為MainThread,也就是主程序占一個(gè)線程,這個(gè)線程和之后用Thread新加的線程是相互獨(dú)立的,主線程不會(huì)等待其余線程運(yùn)行結(jié)束就會(huì)繼續(xù)往下運(yùn)行。之前不用join()無法計(jì)算運(yùn)行時(shí)間就是因?yàn)橹骶€程先運(yùn)行完了。
  • Thread表示運(yùn)行這個(gè)函數(shù)啟動(dòng)一個(gè)新的線程,在其中加一個(gè)name參數(shù)指定這個(gè)函數(shù)線程名,則在這個(gè)函數(shù)內(nèi)打印線程名就顯示這里name參數(shù)對(duì)應(yīng)值
  • 在循環(huán)中打印有兩種。第一種print(threading.current_thread().name)則是MainThread;第二種print(th.name)則是thread 1

(2)Thread函數(shù)

上面我們使用了Thread函數(shù)的target name參數(shù),下面來說一下它的其他參數(shù)

  • args指定target對(duì)應(yīng)函數(shù)的參數(shù),用元組傳入,比如args = (3, )
  • daemon主線程默認(rèn)是False,如果沒有指定則繼承父線程的值。True則如果主線程運(yùn)行結(jié)束,該線程也停止運(yùn)行;False則該線程會(huì)繼續(xù)運(yùn)行直到運(yùn)行結(jié)束,無視主線程如何。(要看這個(gè)參數(shù)的效果要在py文件中編寫代碼,在cmd里運(yùn)行,不能在jupyter notebook里,因?yàn)檫@里會(huì)多出一些線程干擾)
  • group是預(yù)留的一個(gè)參數(shù),用于以后擴(kuò)展ThreadGroup類,現(xiàn)在沒用

(3)Thread對(duì)象

上面threading.Threadthreading.current_thread()都創(chuàng)建了一個(gè)Thread對(duì)象,Thread對(duì)象有如下屬性和方法

  • getName() .name 獲取線程名
  • setName() 設(shè)置線程名
  • start() join()這兩個(gè)之前說過了
  • join()有一個(gè)timeout參數(shù),表示等待這個(gè)線程結(jié)束時(shí),如果等待時(shí)間超過這個(gè)時(shí)間,就不再等,繼續(xù)進(jìn)行下面的代碼,但是這個(gè)線程不會(huì)被中斷
  • run() 也是運(yùn)行這個(gè)線程,但是必須等到這個(gè)線程運(yùn)行結(jié)束才會(huì)繼續(xù)執(zhí)行之后的代碼(如果將上面的start全換成run則相當(dāng)于沒有開多線程)
  • is_alive()如果該線程還沒運(yùn)行完,就是True否則False
  • daemon 返回該線程的daemon
  • setDaemon(True)設(shè)置線程的daemon

(4)threading

一些直接調(diào)用的變量

  • threading.currentThread(): 返回當(dāng)前的線程變量
  • threading.enumerate(): 返回一個(gè)包含正在運(yùn)行的線程的list
  • threading.activeCount(): 返回正在運(yùn)行的線程數(shù)量,與len(threading.enumerate())有相同的結(jié)果

?

?

參考

轉(zhuǎn)載于:https://www.cnblogs.com/JetpropelledSnake/p/8931194.html

總結(jié)

以上是生活随笔為你收集整理的Python Web学习笔记之Python多线程基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。