一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python用threading實現多線程詳解

Python用threading實現多線程詳解

2020-09-19 15:08Typecho Python

這篇文章主要給大家介紹了Python用threading實現多線程的方法示例,文中介紹的很詳細,對大家具有一定的參考借鑒價值,有需要的朋友們下面來一起學習學習吧。

多線程

多線程是個提高程序運行效率的好辦法,本來要順序執行的程序現在可以并行執行,可想而知效率要提高很多。但是多線程也不是能提高所有程序的效率。程序的兩個極端是‘CPU 密集型'和‘I/O 密集型'兩種,多線程技術比較適用于后者,因為在串行結構中當你去讀寫磁盤或者網絡通信的時候 CPU 是閑著的,畢竟網絡比磁盤要慢幾個數量級,磁盤比內存慢幾個數量級,內存又比 CPU 慢幾個數量級。多線程技術就可以同時執行,比如你的程序需要發送 N 個 http 數據包(10 秒),還需要將文件從一個位置復制到另一個位置(20 秒),然后還需要統計另一個文件中'hello,world'字符串的出現次數(4 秒),現在一共是要用 34 秒。但是因為這些操作之間沒有關聯,所以可以寫成多線程程序,幾乎只需要 20 秒就完成了。這是針對 I/O 密集型的,如果是 CPU 密集型的就不行了。比如我的程序要計算 1000 的階乘(10 秒),還要計算 100000 的累加(5 秒),那么即使程序是并行的,還是會要用 15 秒,甚至更多。因為當程序使用 CPU 的時候 CPU 是通過輪轉來執行的,IO 密集型的程序可以在 IO 的同時用 CPU 計算,但是這里的 CPU 密集型就只能先執行一會兒線程 1 再執行一會兒線程 2。所以就需要 15 秒,甚至會更多,因為 CPU 在切換的時候需要耗時。解決 CPU 密集型程序的多線程問題就是 CPU 的事情了,比如 Intel 的超線程技術,可以在同一個核心上真正的并行兩個線程,所以稱之為‘雙核四線程'或者‘四核八線程',我們這里具體的先不談,談我也不知道。

Python 騙人

說了這么多多線程的好處,但是其實 Python 不支持真正意義上的多線程編程。在 Python 中有一個叫做 GIL 的東西,中文是 全局解釋器 ,這東西控制了 Python,讓 Python 只能同時運行一個線程。相當于說真正意義上的多線程是由 CPU 來控制的,Python 中的多線程由 GIL 控制。如果有一個 CPU 密集型程序,用 C 語言寫的,運行在一個四核處理器上,采用多線程技術的話最多可以獲得 4 倍的效率提升,但是如果用 Python 寫的話并不會有提高,甚至會變慢,因為線程切換的問題。所以 Python 多線程相對更加適合寫 I/O 密集型程序,再說了真正的對效率要求很高的 CPU 密集型程序都用 C/C++ 去了。

第一個多線程

Python 中多線程的庫一般用thread和threading這兩個,thread不推薦新手和一般人使用,threading模塊就相當夠用了。

有一個程序,如下。兩個循環,分別休眠 3 秒和 5 秒,串行執行的話需要 8 秒。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# coding=utf-8
import time
def sleep_3():
 time.sleep(3)
def sleep_5():
 time.sleep(5)
if __name__ == '__main__':
 start_time = time.time()
 print 'start sleep 3'
 sleep_3()
 print 'start sleep 5'
 sleep_5()
 end_time = time.time()
 print str(end_time - start_time) + ' s'

輸出是這樣的

?
1
2
3
start sleep 3
start sleep 5
8.00100016594 s

然后我們對它進行修改,使其變成多線程程序,雖然改動沒有幾行。首先引入了 threading 的庫,然后實例化一個 threading.Thread 對象,將一個函數傳進構造方法就行了。然后調用 Thread 的 start 方法開始一個線程。join() 方法可以等待該線程結束,就像我下面用的,如果我不加那兩個等待線程結束的代碼,那么就會直接執行輸出時間的語句,這樣一來統計的時間就不對了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# coding=utf-8
import time
import threading # 引入threading
def sleep_3():
 time.sleep(3)
def sleep_5():
 time.sleep(5)
if __name__ == '__main__':
 start_time = time.time()
 print 'start sleep 3'
 thread_1 = threading.Thread(target=sleep_3)  # 實例化一個線程對象,使線程執行這個函數
 thread_1.start()  # 啟動這個線程
 print 'start sleep 5'
 thread_2 = threading.Thread(target=sleep_5)  # 實例化一個線程對象,使線程執行這個函數
 thread_2.start()  # 啟動這個線程
 thread_1.join()  # 等待thread_1結束
 thread_2.join()  # 等待thread_2結束
 end_time = time.time()
 print str(end_time - start_time) + ' s'

執行結果是這樣的

?
1
2
3
start sleep 3
start sleep 5
5.00099992752 s

daemon 守護線程

在我們理解中守護線程應該是很重要的,類比于 Linux 中的守護進程。但是在threading.Thread中偏偏不是。

如果把一個線程設置為守護線程,就表示這個線程是不重要的,進程退出的時候不需要等待這個線程執行完成。 ---------《Python 核心編程 第三版》

在 Thread 對象中默認所有線程都是非守護線程,這里有兩個例子說明區別。這段代碼執行的時候就沒指定my_thread的daemon屬性,所以默認為非守護,所以進程等待他結束。最后就可以看到 100 個 hello,world

?
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# coding=utf-8
import threading
def hello_world():
 for i in range(100):
  print 'hello,world'
if __name__ == '__main__':
 my_thread = threading.Thread(target=hello_world)
 my_thread.start()

這里設置了my_thread為守護線程,所以進程直接就退出了,并沒有等待他的結束,所以我們看不到 100 個 hello,world 只有幾個而已。甚至還會拋出一個異常告訴我們有線程沒結束。

?
1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# coding=utf-8
import threading
def hello_world():
 for i in range(100):
  print 'hello,world'
if __name__ == '__main__':
 my_thread = threading.Thread(target=hello_world)
 my_thread.daemon = True # 設置了標志位True
 my_thread.start()

傳個參數

之前的代碼都是直接執行一段代碼,沒有過參數的傳遞,那么怎么傳遞參數呢?其實還是很簡單的。threading.Thread(target=hello_world, args=('hello,', 'world'))就可以了。args 后面跟的是一個元組,如果沒有參數可以不寫,如果有參數就直接在元組里按順序添加就行了。

?
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# coding=utf-8
import threading
def hello_world(str_1, str_2):
 for i in range(10):
  print str_1 + str_2
if __name__ == '__main__':
 my_thread = threading.Thread(target=hello_world, args=('hello,', 'world')) # 這里傳遞參數
 my_thread.start()

再來個多線程

threading 有三種創建 Thread 對象的方式,但是一般只會用到兩種,一種是上面0X02說的傳個函數進去,另一種就是這里說的繼承threading.Thread。在這兒我們自己定義了兩個類,類里重寫了 run() 方法,也就是調用 start() 之后執行的代碼,開啟線程就和之前開啟是一樣的。之前的方式更面向過程,這個更面向對象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# coding=utf-8
import threading
class MyThreadHello(threading.Thread):
 def run(self):
  for i in range(100):
   print 'hello'
class MyThreadWorld(threading.Thread):
 def run(self):
  for i in range(100):
   print 'world'
if __name__ == '__main__':
 thread_hello = MyThreadHello()
 thread_world = MyThreadWorld()
 thread_hello.start()
 thread_world.start()

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

原文鏈接:http://blog.just666.cn/index.php/archives/45/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本aaaa级| 欧美乱妇高清无乱码视频在线 | 好紧好爽的午夜寂寞视频 | 国产成人精品午夜免费 | 亚洲国产午夜看片 | 亚洲国产麻豆 | 国产趴着打光屁股sp抽打 | 91桃花视频| 全日爱韩国视频在线观看 | 国产精品国产香蕉在线观看网 | 国产东北3p真实在线456视频 | 水蜜臀 | 成人免费网站视频ww | 久久亚洲精品专区蓝色区 | 国产自在自线午夜精品之la | 日本无遮挡亲吻膜下面免费 | 国产精品四虎在线观看免费 | 精品国语国产在线对白 | 国产精品秒播无毒不卡 | 无限时间看片在线观看 | 亚洲欧美日韩高清 | 国产精品日韩欧美在线 | 狠狠搞视频 | 天天做天天爱天天一爽一毛片 | 亚洲精品国产精麻豆久久99 | 五月婷婷俺来也 | 亚洲国产精品无码中文字幕 | 日本海鸣馆 | 国产一卡2卡3卡四卡精品网站 | 久久久久激情免费观看 | 国内精品久久久久小说网 | 美女被狂揉下部羞羞动漫 | chinese壮直男gay老年人 | 久久久精品成人免费看 | 无码毛片内射白浆视频 | 色哟呦| 国产精品视频免费看 | 精品一卡2卡3卡4卡5卡亚洲 | 久久黄色精品视频 | 网站在线观看 | 日韩一区二区在线视频 |