詳解Python多線程_python

來源:互聯網
上載者:User

本文執行個體為大家解析了Python多線程,供大家參考,具體內容如下

1、多線程的理解

多進程和多線程都可以執行多個任務,線程是進程的一部分。線程的特點是線程之間可以共用記憶體和變數,資源消耗少(不過在Unix環境中,多進程和多線程資源調度消耗差距不明顯,Unix調度較快),缺點是線程之間的同步和加鎖比較麻煩。

2、Python多線程建立

在Python中,同樣可以實現多線程,有兩個標準模組thread和threading,不過我們主要使用更進階的threading模組。使用例子:

import threadingimport time def target(): print 'the curent threading %s is running' % threading.current_thread().name time.sleep(1) print 'the curent threading %s is ended' % threading.current_thread().name print 'the curent threading %s is running' % threading.current_thread().namet = threading.Thread(target=target) t.start()t.join()print 'the curent threading %s is ended' % threading.current_thread().name 

輸出:

the curent threading MainThread is runningthe curent threading Thread-1 is runningthe curent threading Thread-1 is endedthe curent threading MainThread is ended

start是啟動線程,join是阻塞當前線程,即使得在當前線程結束時,不會退出。從結果可以看到,主線程直到Thread-1結束之後才結束。

Python中,預設情況下,如果不加join語句,那麼主線程不會等到當前線程結束才結束,但卻不會立即殺死該線程。如不加join輸出如下:

the curent threading MainThread is runningthe curent threading Thread-1 is running the curent threading MainThread is endedthe curent threading Thread-1 is ended

但如果為線程執行個體添加t.setDaemon(True)之後,如果不加join語句,那麼當主線程結束之後,會殺死子線程。代碼:

import threadingimport timedef target(): print 'the curent threading %s is running' % threading.current_thread().name time.sleep(4) print 'the curent threading %s is ended' % threading.current_thread().nameprint 'the curent threading %s is running' % threading.current_thread().namet = threading.Thread(target=target)t.setDaemon(True)t.start()t.join()print 'the curent threading %s is ended' % threading.current_thread().name

輸出如下:

the curent threading MainThread is runningthe curent threading Thread-1 is runningthe curent threading MainThread is ended

如果加上join,並設定等待時間,就會等待線程一段時間再退出:

import threadingimport timedef target(): print 'the curent threading %s is running' % threading.current_thread().name time.sleep(4) print 'the curent threading %s is ended' % threading.current_thread().nameprint 'the curent threading %s is running' % threading.current_thread().namet = threading.Thread(target=target)t.setDaemon(True)t.start()t.join(1)

輸出:

the curent threading MainThread is runningthe curent threading Thread-1 is runningthe curent threading MainThread is ended

主線程等待1秒,就自動結束,並殺死子線程。如果join不加等待時間,t.join(),就會一直等待,一直到子線程結束,輸出如下:

the curent threading MainThread is runningthe curent threading Thread-1 is runningthe curent threading Thread-1 is endedthe curent threading MainThread is ended

3、線程鎖和ThreadLocal

(1)線程鎖

對於多線程來說,最大的特點就是線程之間可以共用資料,那麼共用資料就會出現多線程同時更改一個變數,使用同樣的資源,而出現死結、資料錯亂等情況。

假設有兩個全域資源,a和b,有兩個線程thread1,thread2. thread1佔用a,想訪問b,但此時thread2佔用b,想訪問a,兩個線程都不釋放此時擁有的資源,那麼就會造成死結。

對於該問題,出現了Lock。 當訪問某個資源之前,用Lock.acquire()鎖住資源,訪問之後,用Lock.release()釋放資源。

a = 3lock = threading.Lock()def target(): print 'the curent threading %s is running' % threading.current_thread().name time.sleep(4) global a lock.acquire() try: a += 3 finally: lock.release() print 'the curent threading %s is ended' % threading.current_thread().name print 'yes'

用finally的目的是防止當前線程無線佔用資源。

(2)ThreadLocal

介紹完線程鎖,接下來出場的是ThreadLocal。當不想將變數共用給其他線程時,可以使用局部變數,但在函數中定義局部變數會使得在函數之間傳遞特別麻煩。ThreadLocal是非常牛逼的東西,它解決了全域變數需要枷鎖,局部變數傳遞麻煩的兩個問題。通過線上程中定義:

local_school = threading.local()

此時這個local_school就變成了一個全域變數,但這個全域變數只在該線程中為全域變數,對於其他線程來說是局部變數,別的線程不可更改。 def process_thread(name):# 綁定ThreadLocal的student: local_school.student = name

這個student屬性只有本線程可以修改,別的線程不可以。代碼:

local = threading.local()def func(name): print 'current thread:%s' % threading.currentThread().name local.name = name print "%s in %s" % (local.name,threading.currentThread().name)t1 = threading.Thread(target=func,args=('haibo',))t2 = threading.Thread(target=func,args=('lina',))t1.start()t2.start()t1.join()t2.join()

從代碼中也可以看到,可以將ThreadLocal理解成一個dict,可以綁定不同變數。

ThreadLocal用的最多的地方就是每一個線程處理一個HTTP請求,在Flask架構中利用的就是該原理,它使用的是基於Werkzeug的LocalStack。

4、Map實現多線程

對於多線程的使用,我們經常是用thread來建立,比較繁瑣:

class MyThread(threading.Thread): def init(self): threading.Thread.init(self)def run(self): lock.acquire() print threading.currentThread().getName() lock.release() def build_worker(num): workers = [] for t in range(num): work = MyThread() work.start() workers.append(work) return workersdef producer(): threads = build_worker(4) for w in threads: w.join() print 'Done'

如果要建立更多的線程,那就要一一加到裡面,操作麻煩,代碼可讀性也變差。在Python中,可以使用map函數簡化代碼。map可以實現多任務的並發,簡單樣本:

複製代碼 代碼如下:
urls = ['http://www.baidu.com','http://www.sina.com','http://www.qq.com']
results=map(urllib2.urlopen,urls)

map將urls的每個元素當做參數分別傳給urllib2.urlopen函數,並最後把結果放到results列表中,map 函數一手包辦了序列操作、參數傳遞和結果儲存等一系列的操作。 其原理:

map函數負責將線程分給不同的CPU。

在 Python 中有個兩個庫包含了 map 函數: multiprocessing 和它鮮為人知的子庫 multiprocessing.dummy.dummy 是 multiprocessing 模組的完整複製,唯一的不同在於 multiprocessing 作用於進程,而 dummy 模組作用於線程。代碼:

import urllib2 from multiprocessing.dummy import Pool as ThreadPool urls = ['http://www.baidu.com','http://www.sina.com','http://www.qq.com'] pool = ThreadPool() results = pool.map(urllib2.urlopen,urls)print resultspool.close()pool.join() print 'main ended'

pool = ThreadPool()建立了線程池,其預設值為當前機器 CPU 的核心數,可以指定線程池大小,不是越多越好,因為越多的話,線程之間的切換也是很消耗資源的。

results = pool.map(urllib2.urlopen,urls) 該語句將不同的url傳給各自的線程,並把執行後結果返回到results中。

代碼清晰明了,巧妙得完成Threading模組完成的功能。

5、Python多線程的缺陷:

上面說了那麼多關於多線程的用法,但Python多線程並不能真正能發揮作用,因為在Python中,有一個GIL,即全域解釋鎖,該鎖的存在保證在同一個時間只能有一個線程執行任務,也就是多線程並不是真正的並發,只是交替得執行。假如有10個線程炮在10核CPU上,當前工作的也只能是一個CPU上的線程。

6、Python多線程的應用情境。

雖然Python多線程有缺陷,總被人說成是雞肋,但也不是一無用處,它很適合用在IO密集型任務中。I/O密集型執行期間大部分是時間都用在I/O上,如資料庫I/O,較少時間用在CPU計算上。因此該應用情境可以使用Python多線程,當一個任務阻塞在IO操作上時,我們可以立即切換執行其他線程上執行其他IO操作請求。

總結:Python多線程在IO密集型任務中還是很有用處的,而對於計算密集型任務,應該使用Python多進程。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.