1. 程式人生 > 其它 >python進階8-多執行緒和多程序

python進階8-多執行緒和多程序

一、執行緒&程序

對於作業系統來說,一個任務就是一個程序(Process),比如開啟一個瀏覽器就是啟動一個瀏覽器程序,開啟一個記事本就啟動了一個記事本程序,開啟兩個記事本就啟動了兩個記事本程序,開啟一個Word就啟動了一個Word程序。程序是很多資源的集合。

有些程序還不止同時幹一件事,比如Word,它可以同時進行打字、拼寫檢查、列印等事情。在一個程序內部,要同時幹多件事,就需要同時執行多個“子任務”,我們把程序內的這些“子任務”稱為執行緒(Thread)。

由於每個程序至少要幹一件事,所以,一個程序至少有一個執行緒。當然,像Word這種複雜的程序可以有多個執行緒,多個執行緒可以同時執行,多執行緒的執行方式和多程序是一樣的,也是由作業系統在多個執行緒之間快速切換,讓每個執行緒都短暫地交替執行,看起來就像同時執行一樣。當然,真正地同時執行多執行緒需要多核CPU才可能實現。執行緒是最小的執行單元,而程序由至少一個執行緒組成。

我們在做事情的時候,一個人做是比較慢的,如果多個人一起來做的話,就比較快了,程式也是一樣的,我們想執行的速度快一點的話,就得使用多程序,或者多執行緒,在python裡面,多執行緒被很多人詬病,為什麼呢,因為Python的直譯器使用了GIL的一個叫全域性直譯器鎖,它不能利用多核CPU,只能執行在一個cpu上面,但是你在執行程式的時候,看起來好像還是在一起執行的,是因為作業系統輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反覆執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。這個叫做上下文切換。

二、多執行緒

python中的多執行緒使用theading模組

下面是一個簡單多執行緒

import threading
import time

def sayhi(num): # 定義每個執行緒要執行的函式

print(<span class="hljs-string">"running on number:%s"</span> % num)

time.sleep(<span class="hljs-number">3</span>)

if name == 'main':
t1 = threading.Thread(target=sayhi, args=(1

,)) # 生成一個執行緒例項
t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另一個執行緒例項
t1.start() # 啟動執行緒
t2.start() # 啟動另一個執行緒

下面是另一種啟動多執行緒的方式,繼承式

import threading
import time

class MyThread(threading.Thread):
def init(self, num):
threading.Thread.init(self)
self.num = num

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span>(<span class="hljs-params">self</span>):</span>  <span class="hljs-comment"># 定義每個執行緒要執行的函式</span>

    print(<span class="hljs-string">"running on number:%s"</span> % self.num)

    time.sleep(<span class="hljs-number">3</span>)

if name == 'main':
t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()

這兩種方式沒有什麼區別,兩種寫法而已,我個人喜歡用第一種,更簡單一些。

執行緒等待

多執行緒在執行的時候,每個執行緒都是獨立執行的,不受其他的執行緒干擾,如果想在哪個執行緒執行完之後,再做其他操作的話,就得等待它完成,那怎麼等待呢,使用join,等待執行緒結束

import threading
import time

def run():
print('qqq')
time.sleep(1)
print('done!')

lis = []
for i in range(5):
t = threading.Thread(target=run)
lis.append(t)
t.start()
for t in lis:
t.join()
print('over')

或者使用繼承式

import threading
import time

class MyThread(threading.Thread):
def init(self,num):
threading.Thread.init(self)
self.num = num

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span>(<span class="hljs-params">self</span>):</span>
    print(<span class="hljs-string">"running on number:%s"</span> % self.num)
    time.sleep(<span class="hljs-number">3</span>)
    print(<span class="hljs-string">'time end:%s'</span> % self.num)

if name == 'main':
lis = []
for i in range(5):
t = MyThread(i)
lis.append(t)
t.start()
for t in lis:
t.join()
print('over')

如果不加join,執行緒執行後,會立即繼續執行print('over') 然後繼續等執行緒執行完畢;加上join後,Python會等執行緒行結束後,再執行print('over')

守護執行緒

有一種執行緒,它是在後臺執行的,它的任務是為其他執行緒提供服務,這種執行緒被稱為“後臺執行緒(Daemon Thread)”,又稱為“守護執行緒”或“精靈執行緒”。Python 直譯器的垃圾回收執行緒就是典型的後臺執行緒。
後臺執行緒有一個特徵,如果所有的前臺執行緒都死亡了,那麼後臺執行緒會自動死亡。
簡單來說,什麼是守護執行緒呢,就相當於你是一個國王(非守護執行緒),然後你有很多僕人(守護執行緒),這些僕人都是為你服務的,一但你死了,那麼你的僕人都給你陪葬。

import threading

# 定義後臺執行緒的執行緒執行體與普通執行緒沒有任何區別
def action(max):
for i in range(max):
print(threading.current_thread().name + " " + str(i))
t = threading.Thread(target=action, args=(100,), name='後臺執行緒')
# 將此執行緒設定成後臺執行緒
# 也可在建立Thread物件時通過daemon引數將其設為後臺執行緒
t.daemon = True
# 啟動後臺執行緒
t.start()
for i in range(10):
print(threading.current_thread().name + " " + str(i))
# -----程式執行到此處,前臺執行緒(主執行緒)結束------
# 後臺執行緒也應該隨之結束

也可在建立Thread物件時通過daemon引數將其設為後臺執行緒

import threading

# 定義後臺執行緒的執行緒執行體與普通執行緒沒有任何區別
class MyThread(threading.Thread):
def init(self,max,daemon=False):
threading.Thread.init(self)
self.max = max
self.daemon = daemon
def run(self):
for i in range(self.max):
print(threading.current_thread().name + " " + str(i))

# 將此執行緒設定成後臺執行緒
t = MyThread(100,daemon=True)

# 啟動後臺執行緒
t.start()
for i in range(10):
print(threading.current_thread().name + " " + str(i))
# -----程式執行到此處,前臺執行緒(主執行緒)結束------
# 後臺執行緒也應該隨之結束

注意,當前臺執行緒死亡後,Python 直譯器會通知後臺執行緒死亡,但是從它接收指令到做出響應需要一定的時間。如果要將某個執行緒設定為後臺執行緒,則必須在該執行緒啟動之前進行設定。也就是說,將 daemon 屬性設為 True,必須在 start() 方法呼叫之前進行,否則會引發 RuntimeError 異常。

執行緒鎖

執行緒鎖就是,很多執行緒一起在操作一個數據的時候,可能會有問題,就要把這個資料加個鎖,同一時間只能有一個執行緒操作這個資料。

        import threading
        from threading import Lock
        num = 0
        lock = Lock()#申請一把鎖
        def run():
            global num
            lock.acquire()#加鎖
            num+=1
            lock.release()#解鎖
    lis = []
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>):
        t = threading.Thread(target=run)
        t.start()
        lis.append(t)
    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> lis:
        t.join()
    print(<span class="hljs-string">'over'</span>,num)

下面來個簡單的爬蟲,看下多執行緒的效果

        import threading
        import requests,time
        urls  ={
            "baidu":'http://www.baidu.com',
            "blog":'http://www.nnzhp.cn',
            "besttest":'http://www.besttest.cn',
            "taobao":"http://www.taobao.com",
            "jd":"http://www.jd.com",
        }
        def run(name,url):
            res = requests.get(url)
            with open(name+'.html','w',encoding=res.encoding) as fw:
                fw.write(res.text)
    start_time = time.time()
    lis = []
    <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> urls:
        t = threading.Thread(target=run,args=(url,urls[url]))
        t.start()
        lis.append(t)
    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> lis:
        t.join()
    end_time = time.time()
    print(<span class="hljs-string">'run time is %s'</span>%(end_time-start_time))
   
    <span class="hljs-comment">#下面是單執行緒的執行時間</span>
    <span class="hljs-comment"># start_time = time.time()</span>
    <span class="hljs-comment"># for url in urls:</span>
    <span class="hljs-comment">#     run(url,urls[url])</span>
    <span class="hljs-comment"># end_time = time.time()</span>
    <span class="hljs-comment"># print('run time is %s'%(end_time-start_time))</span>

三、多程序

上面說了Python裡面的多執行緒,是不能利用多核CPU的,如果想利用多核CPU的話,就得使用多程序,python中多程序使用multiprocessing模組。

    from multiprocessing import Process
    import time
    def f(name):
        time.sleep(2)
        print('hello', name) 
    p = Process(target=f, args=('niu',))
    p.start()
    p.join()

轉載自https://www.cnblogs.com/feng0815/p/7953788.html