python筆記9 : 多線程

来源:http://www.cnblogs.com/lhly/archive/2017/07/14/7163791.html
-Advertisement-
Play Games

基礎: 什麼是進程(process)? 每一個程式的記憶體是獨立的,例如:world不能訪問QQ。 進程:QQ是以一個整體的形式暴露給操作系統管理,裡面包含了各種資源的調用(記憶體管理、網路介面調用等)。啟動一個QQ,也就是啟動了一個進程。 什麼是線程(thread)? 線程是操作系統能夠進行運算調度的 ...


基礎:

什麼是進程(process)?

每一個程式的記憶體是獨立的,例如:world不能訪問QQ。 

進程:QQ是以一個整體的形式暴露給操作系統管理,裡面包含了各種資源的調用(記憶體管理、網路介面調用等)。啟動一個QQ,也就是啟動了一個進程。

什麼是線程(thread)?

線程是操作系統能夠進行運算調度的最小單位。線程包含在進程之中,是進程中的實際運作單位。

一個進程中最少有一個線程

一個線程時指 進程中一個單一順序的控制流。

一個進程中科院併發多個線程,每條線程並行執行不同的任務,線程與線程之間是相互獨立的。

線程和進程的區別:

進程:對各種資源管理的集合

線程:操作系統最小的調度單位,是一串指令的集合

關係:

進程中第一個線程時主線程,主線程創建其他線程,其他線程也可以創建線程,線程之間是平等的;

進程有父進程、子進程,獨立的記憶體空間,唯一的進程標識符,pid;

什麼是上下文切換?

上下文切換,也稱做進程切換或者任務切換,是指cpu從一個進程或線程切換到另一個進程或線程。舉例說明,如下:

a.開啟QQ和微信,先聊QQ,然後切換到微信進行聊天,再切換到QQ,這個操作就叫做上下文切換。

b.同時開啟多個應用,電腦cpu配置是4核,多個應用之間進行切換時,沒有卡頓現象 也完全感受不到cpu在進行任務切換,因為cpu處理很快,所以應用之間切換沒有卡頓現象;

 

單線程:

import time
import requests

def get_res():
    urls = [
        'http://www.baidu.com',
        'https://www.taobao.com/',
        'https://www.jd.com/',
        'http://www.meilishuo.com/'
    ]
    start = time.time()
    for url in urls:
        print(url)
        resp = requests.get(url)
        print(resp)
    end = time.time()
    print('單線程運行時間:', end - start)

執行結果:

http://www.baidu.com
<Response [200]>
https://www.taobao.com/
<Response [200]>
https://www.jd.com/
<Response [200]>
http://www.meilishuo.com/
<Response [200]>
單線程運行時間: 1.0470597743988037

解釋:

a. cpu順序被請求

b.除非cpu從一個url獲取的響應,否則不會去請求下一個url

c. 網路請求會花費較長的時間,所以cpu在等待網路請求的返回時間內一直處於閑置狀態

 多線程:

import time
import threading

def run(count):
    #每次執行該方法,需要休息2s
    time.sleep(2)
    print(count)

#開始創建多線程
start = time.time()
for i in range(5):
    #創建線程,指定運行哪個函數,也就是指定哪個函數運行需要創建多線程
    #target=要運行的函數名
    # args=函數運行傳入的參數,run方法需要傳入count,把創建
    th = threading.Thread(target=run, args=(i, ))
    #啟動線程
    th.start()
#多線程創建完畢且運行結束
end = time.time()
print('運行時間:', end - start)

運行結果:

運行時間: 0.0
1
0
4
2
3

解釋:

a. 列印出來的運行時間統計的不是多線程的運行時間,因為沒有運行run都要等待2s,所以多線程的運行時間至少為2s,那麼列印的結果是什麼?

  列印的運行時間是 主線程的運行時間,因為在運行python文件時,如果不啟動多線程,至少有一個線程在運行

  線程與線程之間是相互獨立的,最開始運行的是主線程,當運行到threading.Thread時,創建一個線程,創建的線程執行迴圈方,主線程執行其他操作

  主線程不等待其他線程結束後再結束

b. 列印出的count數據是無序的,因為多線程運行run方法,並不是第一個請求結束後才進行下一個請求的,而是創建一個線程後執行run方法,接著創建另一個線程,哪個線程執行完畢就會列印出結果

c. 總共創建了5個線程

 

若想統計多線程總共的執行時間,也就是從開始創建線程 到 線程結束運行之間的時間(不需要考慮線程之間怎麼運行的),操作如下:

join()等待 (等待線程結束)

import time
import threading

def run(count):
    #每次執行該方法,需要休息2s
    time.sleep(2)
    print(count)

#開始創建多線程
start = time.time()
#存放創建的所有線程
threads_list = []
for i in range(5):
    #創建線程,指定運行哪個函數,也就是指定哪個函數運行需要創建多線程
    #target=要運行的函數名
    # args=函數運行傳入的參數,run方法需要傳入count,把創建
    th = threading.Thread(target=run, args=(i, ))
    #啟動線程
    th.start()
    #把啟動的每一個線程添加到線程組內
    threads_list.append(th)

for t in threads_list:
    #主線程迴圈等待每個子線程運行完畢, t代表每個子線程
    t.join()  #等待線程結束

#多線程創建完畢且運行結束
end = time.time()
print('運行時間:', end - start)

執行結果:

0
1
2
4
3
運行時間: 2.0011146068573

 守護線程

守護線程:主線程運行結束後,不管守護線程執行是否結束,都會結束,舉例說明:

比如皇帝有很多僕人,當皇帝死了之後,那麼多僕人就得陪葬。

只要非守護線程結束了,不管守護線程結束沒結束,程式都結束

import threading
import time

def run(count):
    time.sleep(2)
    print(count)

for i in range(5):
    #迴圈創建線程,總共5個線程
    t = threading.Thread(target=run, args=(i, ))
    #設置守護線程,新創建的這些線程都是 主線程的 守護線程, 主線程創建一個線程後 就運行結束了
    t.setDaemon(True)
#啟動線程,守護線程設置必須在start前面
    t.start()
print('over')

GIL 全局解釋器鎖

例如 4核機器上 
Python創建4線程,四個線程均勻分到多核上,但是同時只能一核在處理數據。 
python調用操作系統、C語音的原生介面,在出口做了設置。全局解釋器鎖,保證數據統一 
所以有人說python的線程是假線程。 
在修改數據的時候,為了防止數據改亂了,所以多線程就變成串列處理,但是以為是python在處理,實際上是調用了操作系統的C語音的線程介面,所以中間的過程,python控制不了了,只知道結果。在這種情況下,設置的方式是出口控制,雖然四個線程,但是同一時間只有一個線程在工作。 
  
所以這算是python的一個缺陷,但是也不能說是python的缺陷,是Cpython的缺陷。因為Cpython是C語音寫的,以後python的未來是PYPY。 

線程鎖

線程鎖,又叫互斥鎖

線程之間溝通:保證同一時間只有一個線程修改數據

python2.x 中需要加鎖,Python3.x中加不加鎖都一樣,因為解釋器做了優化

import threading
from threading import Lock

#創建lock對象
num = 0
lock = Lock()   #申請一把鎖,創建鎖的對象
def run2():
    global num
    lock.acquire()      #修改數據前 加鎖
    num += 1
    lock.release()      #修改後釋放解鎖

lis = []
for i in range(5):
    #創建線程
    t = threading.Thread(target=run2)
    #啟動線程
    t.start()
    #將啟動的線程添加到線程組內
    lis.append(t)

for t in lis:
    #等待線程運行結束
    t.join()
#num的值為5,執行多次後,會出現不一樣的值
print('over', num)

RLock 遞歸鎖

大鎖中還有小鎖、遞歸鎖,解鎖時就混了,所以用遞歸鎖,Rlock()

import threading,time

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num +=1
    lock.release()
    return num
def run2():
    print("grab the second part data")
    lock.acquire()
    global  num2
    num2+=1
    lock.release()
    return num2
def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res,res2)

if __name__ == '__main__':

    num,num2 = 0,0
    lock = threading.RLock()  # 聲明遞歸鎖
    # lock = threading.Lock() # 用互斥鎖,會鎖死了,弄混鎖情況,可以試一下
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

    while threading.active_count() != 1:
        print(threading.active_count())
    else:
        print('----all threads done---')
        print(num,num2)

 多線程的另一種寫法:

import threading
import time
class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        self.num = num
    def run(self):  # 定義每個線程要運行的函數
        print("running on number:%s" % self.num)
        time.sleep(3)

if __name__ == '__main__':
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()

多進程(瞭解即可):

python裡面的多線程,是不能利用多核cpu的,如果想利用多核cpu的話,就得使用多進程

多進程適用CPU密集型任務

多線程適用io密集型任務

from multiprocessing import Process
def f(name):
    time.sleep(2)
    print('hello', name)

if __name__ == '__main__':
    for i in range(10):
        p = Process(target=f, args=('niu',))
        p.start()
轉載請務必保留此出處:http://www.cnblogs.com/lhly/p/7163791.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 轉載請註明出處http://blog.csdn.net/evankaka 摘要:本文主要講瞭如何在阿裡雲上安裝JDK、Tomcat以及其配置過程。最後以一個實例來演示在阿裡雲上部署Java web項目。 本文實例訪問:http://120.24.19.24:8080/JavaHelloWorld-0 ...
  • 1、藉助列表 上述代碼實現了隨機驗證碼的功能,但是只能生成包含小寫字母的隨機驗證碼;並且我們也是藉助列表完成的,字元串的拼接加上列表,字元串jion()方法,生成了隨機驗證碼。下麵我們來嘗試也生成大寫驗證碼的方法。 由於數據之間有三種關係,大於,小於,等於,這樣把每種情況都進行分析,就能生成三種隨機 ...
  • 作者:匿名用戶鏈接:https://www.zhihu.com/question/21653286/answer/95532074來源:知乎著作權歸作者所有,轉載請聯繫作者獲得授權。 想學習Python3,但是暫時又離不開Python2。在Windows上如何讓它們共存呢? 目前國內網站經常會讓大家 ...
  • C++隨機數 一、 產生1-52的隨機數 ...
  • 實際開發中,Junit單元測試是必不可少的。在spring boot 中可以通過測試模塊(spring boot starter test)快速使用單元測試功能。 開始 本示例在 spring boot 1.5.4 版本測試通過 1、pom.xml中添加配置spring boot starter t ...
  • hibernate一級緩存 1.Hibernate一級緩存又稱為“Session緩存”,“會話級緩存”。 2.通過Session從資料庫查詢實體時會把實體在記憶體中存儲起來,下一次查詢同一實體時不再從資料庫獲取,而是從記憶體中獲取,這就是緩存 3.一級緩存的生命周期和Session相同,Session銷 ...
  • 今天總結一下最基礎的輸入輸出和運算符 輸入: python3里都是input("") input() name = input() #輸入的值會直接賦值給name name = input("請輸入你的姓名:") #("")里的話是輸入提示信息 ps: 輸入的值會直接賦值給name。 input輸入 ...
  • 變數是保存存儲值的記憶體位置。也就是說,當創建一個變數時,可以在記憶體中保留一些空間。 基於變數的數據類型,解釋器分配記憶體並決定可以存儲在保留的存儲器中的內容。 因此,通過為變數分配不同的數據類型,可以在這些變數中存儲的數據類型為整數,小數或字元等等 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...