Python學習——Python線程

来源:http://www.cnblogs.com/huan-ge/archive/2017/06/27/7067931.html
-Advertisement-
Play Games

一、線程創建 註解:Thread(group=None,target=None,name=None,args=(),kwargs={})group:線程組,目前還沒有實現,庫引用時提示必須是Nonetarget:要執行的方法name:線程名args/kwargs:要傳入方法的參數,args和kwar ...


一、線程創建

 1 #方法一:將要執行的方法作為參數傳給Thread的構造方法
 2 import threading
 3 import time
 4 
 5 def show(arg):
 6     time.sleep(2)
 7     print('thread' + str(arg))
 8 
 9 for i in range(10):
10     t = threading.Thread(target=show,args=(i,))
11     time.sleep(2)
12     t.start()
13 
14 #方法2:從Thread繼承,並重寫run()
15 class MyThread(threading.Thread):
16     def __init__(self,num):
17         threading.Thread.__init__(self)
18         self.num = num
19 
20     def run(self)):#定義每個線程要運行的函數
21         print("running on number:%s" %self.num)
22         time.sleep(3)
23 
24 
25 if __name__ ==  '__main__':
26     t1 = MyThread(1)
27     t2 = MyThread(2)
28     t1.start()
29     time.sleep(3)
30     t2.start()

註解:
Thread(group=None,target=None,name=None,args=(),kwargs={})
group:線程組,目前還沒有實現,庫引用時提示必須是None
target:要執行的方法
name:線程名
args/kwargs:要傳入方法的參數,args和kwargs兩個參數其實是二選一
#實例方法
isAlive():返回線程是否在運行
get/setName(name):獲取/設置線程名
is/setDaemon(bool):獲取/設置是否守護線程。初始值從創建該線程的線程繼承,當沒有非守護線程仍在運行時,程式將終止
start():啟動線程
join([timeout]):阻塞當前上下文環境的線程。

二、Python多線程用法

 1 import threading
 2 from time import ctime,sleep
 3 
 4 def music(func):
 5     for i in range(2):
 6         print("I was listening to %s. %s" %(func,ctime()))
 7         sleep(1)
 8 def move(func):
 9     for i in range(2):
10         print("I was at the %s! %s" %(func,ctime()))
11         sleep(5)
12 
13 threads = []
14 t1 = threading.Thread(target=music,args=('童話鎮',))
15 threads.append(t1)
16 t2 = threading.Thread(target=move,args=('變形金剛',))
17 threads.append(t2)
18 
19 if __name__ == '__main__':
20     for t in threads:
21         t.setDaemon(True)
22         t.start()
23 
24     print("all over %s" %ctime())

註:

threads = []

t1 = threading.Thread(target=music,args=('童話鎮',))

threads.append(t1)

  創建了threads數組,創建線程t1,使用threading.Thread()方法,在這個方法中調用music方法target=music,args方法對music進行傳參。 把創建好的線程t1裝到threads數組中。

  接著以同樣的方式創建線程t2,並把t2也裝到threads數組。

for t in threads:

  t.setDaemon(True)

  t.start()

最後通過for迴圈遍曆數組。(數組被裝載了t1和t2兩個線程)

setDaemon()

  setDaemon(True)將線程聲明為守護線程,必須在start() 方法調用之前設置,如果不設置為守護線程程式會被無限掛起。子線程啟動後,父線程也繼續執行下去,當父線程執行完最後一條語句print "all over %s" %ctime()後,沒有等待子線程,直接就退出了,同時子線程也一同結束。

       serDeamon(False)(預設)前臺線程,主線程執行過程中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,主線程停止。

運行結果:

I was listening to 童話鎮. Thu Jun 22 23:23:07 2017
I was at the 變形金剛! Thu Jun 22 23:23:07 2017
all over Thu Jun 22 23:23:07 2017

         從執行結果來看,子線程(muisc 、move )和主線程(print "all over %s" %ctime())都是同一時間啟動,但由於主線程執行完結束,所以導致子線程也終止。 

調整程式:

 

1 if __name__ == '__main__':
2     for t in threads:
3         t.setDaemon(True)
4         t.start()
5     
6     t.join()
7 
8     print "all over %s" %ctime()

         加了join()方法,用於等待線程終止。join()的作用是,在子線程完成運行之前,這個子線程的父線程將一直被阻塞。

         join()方法的位置是在for迴圈外的,也就是說必須等待for迴圈里的兩個進程都結束後,才去執行主進程。

運行結果:

1 ############運行結果###################
2 I was listening to 童話鎮. Thu Jun 22 23:34:22 2017
3 I was at the 變形金剛! Thu Jun 22 23:34:22 2017
4 I was listening to 童話鎮. Thu Jun 22 23:34:23 2017
5 I was at the 變形金剛! Thu Jun 22 23:34:27 2017
6 all over Thu Jun 22 23:34:32 2017

從結果的時間可以看出每首歌之間等待1秒,電影之間等待5秒,但是是同步進行的,總的時間為5秒

三、線程鎖(LOCK,RLOCK)
         由於線程之間是進行隨機調度,並且每個線程可能只執行n條執行之後,當多個線程同時修改同一條數據時可能會出現臟數據,所以,出現了線程鎖 - 同一時刻允許一個線程執行操作。

  Lock(指令鎖)是可用的最低級的同步指令。Lock處於鎖定狀態時,不被特定的線程擁有。Lock包含兩種狀態——鎖定和非鎖定,以及兩個基本的方法。

  可以認為Lock有一個鎖定池,當線程請求鎖定時,將線程至於池中,直到獲得鎖定後出池。池中的線程處於狀態圖中的同步阻塞狀態。  

  RLock(可重入鎖)是一個可以被同一個線程請求多次的同步指令。RLock使用了“擁有的線程”和“遞歸等級”的概念,處於鎖定狀態時,RLock被某個線程擁有。擁有RLock的線程可以再次調用acquire(),釋放鎖時需要調用release()相同次數。

  可以認為RLock包含一個鎖定池和一個初始值為0的計數器,每次成功調用 acquire()/release(),計數器將+1/-1,為0時鎖處於未鎖定狀態。

  簡言之:Lock屬於全局,Rlock屬於線程。

1,未使用鎖

 1 import threading
 2 import time
 3 
 4 num = 0
 5 
 6 def show(arg):
 7     global num
 8     time.sleep(1)
 9     num +=1
10     print(num)
11 
12 for i in range(10):
13     t = threading.Thread(target=show, args=(i,))
14     t.start()
15 
16 print('main thread stop')

多次運行可能產生混亂。這種場景就是適合使用鎖的場景。

2.使用鎖

 1 import threading
 2 import time
 3 
 4 num = 0
 5 lock = threading.RLock()
 6 
 7 # 調用acquire([timeout])時,線程將一直阻塞,
 8 # 直到獲得鎖定或者直到timeout秒後(timeout參數可選)。
 9 # 返回是否獲得鎖。
10 def show(arg):
11     lock.acquire()
12     global num
13     time.sleep(1)
14     num +=1
15     print(num)
16     lock.release()
17 
18 for i in range(10):
19     t = threading.Thread(target=show, args=(i,))
20     t.start()
21 
22 print('main thread stop')

加上鎖後數字會一步步列印出來,不會因為擁堵而錯亂的情況!


四、信號量(Semaphore)

互斥鎖 同時只允許一個線程更改數據,而Semaphore是同時允許一定數量的線程更改數據 ,比如廁所有3個坑,那最多只允許3個人上廁所,後面的人只能等裡面有人出來了才能再進去。

 1 import threading, time
 2 
 3 def run(n):
 4     semaphore.acquire()
 5     time.sleep(3)
 6     print("run the thread: %s" % n)
 7     semaphore.release()
 8 
 9 if __name__ == '__main__':
10     num = 0
11     semaphore = threading.BoundedSemaphore(5)  # 最多允許5個線程同時運行
12     for i in range(20):
13         t = threading.Thread(target=run, args=(i,))
14         t.start()

 五、事件(event)

Python線程的事件主要用於主線程式控制制其他線程的執行,事件主要提供了三個方法:set、wait、clear

事件處理的機制:全局定義了一個“Flag”,如果“Flag”值為 False,那麼當程式執行 event.wait 方法時就會阻塞,如果“Flag”值為True,那麼event.wait 方法時便不再阻塞。

clear:將“Flag”設置為False

set:將“Flag”設置為True

用threading.Event實現線程間的通訊

threading.Event使一個線程等待其他線程的通知,把這個Event傳遞到線程對象中,Event預設內置了一個標誌,初始值為False。
一旦該線程通過wait()方法進入等待狀態,直到另一個線程調用該Event的set()方法將內置標誌設置為True時,
該Event會通知所有等待狀態的線程恢復運行。

 1 import threading
 2 
 3 def do(event):
 4     print('start')
 5     event.wait()
 6     print('end')
 7 
 8 event_obj = threading.Event()
 9 
10 for i in range(10):
11     t = threading.Thread(target=do, args=(event_obj,))
12     t.start()
13 
14 event_obj.clear() #繼續阻塞
15 
16 inp = input('input:')
17 if inp == 'true':
18     event_obj.set()  # 喚醒

六、條件(condition)
所謂條件變數,即這種機制是在滿足特定條件之後,線程才可以訪問相關的數據!

它使用Condition類來完成,由於它也可以像鎖機制那樣用,所以它也有acquire方法和release方法,而且它還有wait,notify,notifyAll方法

一個簡單的生產消費者模型,通過條件變數的控制產品數量的增減,調用一次生產者產品就是+1,調用一次消費者產品就會-1. 使用 Condition 類來完成,由於它也可以像鎖機制那樣用,所以它也有 acquire 方法和 release 方法,而且它還有 wait, notify, notifyAll 方法。
 1 import threading
 2 import  time
 3 
 4 # 產品類
 5 class Goods:
 6     def __init__(self):
 7         self.count = 0
 8 
 9     def add(self, num=1):
10         self.count += num
11 
12     def sub(self):
13         if self.count >= 0:
14             self.count -= 1
15 
16     def empty(self):
17         return self.count <= 0
18 
19 # 生產者
20 class Producer(threading.Thread):
21     def __init__(self, condition, goods, sleeptime=1):
22         threading.Thread.__init__(self)
23         self.cond = condition
24         self.goods = goods
25         self.sleeptime = sleeptime
26 
27     def run(self):
28         cond = self.cond
29         goods = self.goods
30         while True:
31             # 鎖住資源
32             cond.acquire()
33             goods.add()
34             print("產品數量:", goods.count, "生產者線程")
35             # 喚醒所有等待的線程 -> 其實就是喚醒消費者進程
36             cond.notifyAll()
37             # 解鎖資源
38             cond.release()
39             time.sleep(self.sleeptime)
40 
41 
42 # 消費者
43 class Consumer(threading.Thread):
44     def __init__(self, condition, goods, sleeptime=2):
45         threading.Thread.__init__(self)
46         self.cond = condition
47         self.goods = goods
48         self.sleeptime = sleeptime
49 
50     def run(self):
51         cond = self.cond
52         goods = self.goods
53 
54         while True:
55             time.sleep(self.sleeptime)
56             # 鎖住資源
57             cond.acquire()
58             # 如無產品則讓線程等待
59             while goods.empty():
60                 cond.wait()
61             goods.sub()
62             print("產品數量:", goods.count, "消費者線程")
63             
64 
65 g = Goods()
66 c = threading.Condition()
67 pro = Producer(c, g)
68 pro.start()
69 con = Consumer(c, g)
70 con.start()

七、定時器(Timer)

 1 import threading
 2 def SayHello():
 3     print("hello world!")
 4     t=threading.Timer(3,SayHello)
 5     t.start()
 6 def other_func():
 7     print("let me running!")
 8     t=threading.Timer(1,other_func)
 9     t.start()
10 
11 if __name__ == "__main__":
12     SayHello()
13     other_func()

 

 

 

 

 

 

 

 

 

 


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

-Advertisement-
Play Games
更多相關文章
  • program ex1807;var n,i,j,t,f,l,q,z:integer;s1,s2:longint; a:array[1..20,1..20] of integer;begin readln(n); t:=1; f:=1; l:=n;i:=1;q:=1;z:=n; while t<=n ...
  • #include <bits/stdc++.h>using namespace std;int main(){ string s; int i=1,n,z; cin>>s; z=s[0]-48;n=s.length(); while(i<n) { if(s[i]=='+') z=z+(s[i+1]- ...
  • 在servlet中,轉發和重定向是由request和response完成的。兩者之間的區別請看我之前的文章。那麼在springMVC中是如何完成的呢? /**轉發**/ @RequestMapping("/login.do") public String login(HttpServletReque ...
  • 真是前所未有的大失誤啊,竟然快兩個月忘記寫博客了! 公司的項目組連著解散了倆,挺動蕩的! 終於把欠公司的錢還上了,這次改欠支付寶了! 摩托車也練的可以正常騎行了,拉過幾次高速,最快到111了,油門還沒到底,不知道磨合期過了之後是不是能更快一些! 房貸也開始還了,現在每個月都是收支都是負數,情況不太樂 ...
  • python中的多線程其實並不是真正的多線程,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進程。Python提供了非常好用的多進程包multiprocessing,只需要定義一個函數,Python會完成其他所有事情。藉助這個包,可以輕鬆完成從單進程到併發執行的轉換。mul ...
  • 轉載需註明原文地址和作者兩項內容。 正則表達式目的是能夠快速處理字元串內容,主要用於找出指定的字元串,配合其他操作完成任務。使用正則表達式時要瞭解自己語言的特性,python中的正則表達式預設情況是貪婪模式,也就是不限制的情況下會儘可能多得匹配字元串。 0x00 基礎語法 0x01 python正則 ...
  • 廢話不說,直接給思路 gitlab重部署後新加用戶不發送激活郵件,配置如下: 首先確認配置沒問題,其次查看日誌production.log log沒有給出錯誤信息。那就直接開大招 確保method為smtp,錯了就是配置寫錯了或者沒被正確載入 確保配置是我們要的 發送測試郵件,此時會列印詳細錯誤 T ...
  • 1、把lib.py里的代碼導入index.py,然後使用lib.py代碼: 導入之後會生成一個.pyc文件,即位元組碼文件。 2、解釋器 即用python來執行hello.py腳本. 3、編碼的基本知識 unicode即萬國碼,utf8是對unicode的精簡,gbk是與utf8同級別的編碼方式。 4 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...