1. 程式人生 > >【python標準庫學習】thread,threading(一)多線程的介紹和使用

【python標準庫學習】thread,threading(一)多線程的介紹和使用

超時 targe 同步問題 線程 線程同步鎖 定義類 查看 兩個 key

在單個程序中我們經常用多線程來處理不同的工作,尤其是有的工作需要等,那麽我們會新建一個線程去等然後執行某些操作,當做完事後線程退出被回收。當一個程序運行時,就會有一個進程被系統所創建,同時也會有一個線程運行,這個線程就是主線程main,在主線程中所創建的新的線程都是子線程,子線程通常都是做一些輔助的事。python中提供了thread和threading兩個模塊來支持多線程。這篇介紹一下python的多線程和基本使用,下一篇介紹python多線程同步問題。

python中使用線程有兩種方式,第一種是用thread模塊的start_new_thread函數,另一種是用threading模塊的Thread類來包裝線程對象。

1.使用thread模塊

使用thread模塊的start_new_thread函數創建線程並啟動。start_new_thread函數原型:

thread.start_new_thread(function, args[, kwargs])

>>> help(thread.start_new_thread)

 

Help on built-in function start_new_thread in module thread:

 

start_new_thread(...)

    start_new_thread(function, args[, kwargs])

    (start_new() is an obsolete synonym)

    

    Start a new thread and return its identifier.  The thread will call the

    function with positional arguments from the tuple args and keyword arguments

    taken from the optional dictionary kwargs.  The thread exits when the

    function returns; the return value is ignored.  The thread will also exit

    when the function raises an unhandled exception; a stack trace will be

    printed unless the exception is SystemExit.

(END) 

  

這個函數創建一個新線程,並立刻執行函數function,args是該函數function的參數,是一個元組,kwargs是可選的,它為函數提供了命名參數字典。該函數返回一個整數,為線程標示符。function函數執行完後線程正常退出,如果執行過程中有未處理的異常,線程會異常退出。

thread模塊的主要函數:

1).start_new_thread()

創建並啟動線程執行function函數,function執行完線程退出,或者遇到未處理的異常線程異常退出。

2).thread.exit()

結束當前線程,會觸發SystemExit異常,如果沒有捕獲處理該異常,線程會退出。

3).thread.get_ident()

得到該線程的標示符,就是新建線程時返回的標示符,是一個整數。

4).thread.interrupt_main

在主線程main中觸發一個KeyboardInterrupt異常,子線程用這個函數來終止主線程。

5).thread.allocate_lock()

創建一個鎖對象LockType,使多個線程同步訪問共享資源。

在python中使用多線程更多的是使用第二種方式,即使用threading模塊。

2.使用threading模塊

threading模塊是對thread模塊的第二次封裝,提供了更好的API來讓我們使用。使用threading實現多線程編程都是使用的Thread類,或者Timer類,Timer是Thread的子類,可以指定時間間隔後在執行某個操作:

 1 from threading import Timer
 2 
 3  
 4 
 5 def main():
 6 
 7     print timer test!
 8 
 9 t = Timer(3, main)
10 
11 t.start()

使用Thread類有兩種方式,一種是直接創建Thread類的實例,另一種方式是自定義類來繼承Thread類。使用Thread類的實例,在它的初始化函數__init__中將可調用的對象作為參數傳入,Thread的初始化函數__init__原型:

__init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None);

group和verbose不知道是什麽東西,target是可調用對象,線程啟動後就執行它,name為線程的名字,默認為"Thread-N",N為數字,args和kwargs是調用target是的參數列表和關鍵字參數。

1 from threading import Thread
2 
3 def main(a, b):
4 
5     print a:%d, b:%d % (a, b)
6 
7 Thread(target=main, name=newThread, args=(1, 2)).start()

自定義類來繼承Thread類,然後重寫run方法實現我們自己的操作。

from threading import Thread

 

 

class MyThread(Thread):

 

    def __init__(self, threadName, a, b):

        Thread.__init__(self, name=threadName)

        self.a = a

        self.b = b

 

    def run(self):

        print a:%d, b:%d % (self.a, self.b)

 

 

myThread = MyThread(newThread, 1, 2)

myThread.start()

邏輯代碼是寫在run方法中的,但是我們啟動線程都是用的start方法,這兩個方法是有區別的,如果直接調用run()方法,只是單純的調用方法,而調用start()方法是將線程從新建狀態啟動編程就緒狀態,等待cpu的調度,這裏涉及到線程的幾種狀態,start()後線程沒有立即運行而是編程就緒狀態,當得到cpu時間片後編程運行狀態,當run方法結束或者有未處理的異常,線程就結束變成死亡狀態等待被回收,在運行狀態如果遇到資源沒有準備好就會變成阻塞狀態,當得到資源後再次編程就緒狀態等待cpu的調度。

threading模塊的主要類:

1).Thread類

上面已經介紹。

2).Timer類

Thread的子類,上面已經介紹。

3).Lock,RLock,Condition類

同步鎖,用於多實現線程同步,資源共享的問題。

4).Event類

用於多線程通信。

多線程同步鎖Lock,RLock,Condition和多線程通信Event後面在多線程同步再介紹。

threading模塊Thread類的主要函數:

1).Thread.getName(),Thread.setName()

獲取和設置線程名字。

2).Thread.ident()

獲取線程的標示符,是一個整數。

3).Thread.is_alive(),Thread.isAlive()

判斷線程是不是活的,即線程是否已經結束。

4).Thread.activeCount()

獲取當前活著的所有線程總數,包括主線程main。

5).Thread.join()

使主線程阻塞,知道該子線程執行完或者超時,它有一個參數timeout表示超時時間,默認為None。

6).Thread.setDaemon()

有一個布爾值的參數,默認為False,該方法設置子線程是否隨主線程一起結束。

看看join方法和setDaemon方法:

import threading, time

 

 

class MyThread(threading.Thread):

 

    def __init__(self):

        threading.Thread.__init__(self)

 

    def run(self):

        print thread start

        time.sleep(3)

        print thread end

 

 

thread1 = MyThread()

thread1.start()

 

time.sleep(1)

 

print start join

#thread1.join()

print end join

輸出結果:

不加thread.join

thread start

start join

end join

thread end

 

加thread.join

thread start

start join

thread end

end join

  主線程中sleep(1)一秒就是為了讓線程被調度,線程中sleep(3)三秒就是為了讓主線程結束,從兩種情況的輸出結果可以看出join的功能。

import threading, time

 

 

class MyThread(threading.Thread):

 

    def __init__(self):

        threading.Thread.__init__(self)

 

    def run(self):

        print ‘thread start‘

        time.sleep(3)

        print ‘thread end‘

 

 

print ‘main start‘

thread1 = MyThread()

#thread1.setDaemon(True)

thread1.start()

 

time.sleep(1)

 

print ‘main end‘

  輸出結果:

setDaemon默認為False

main start

thread start

main end

thread end

 

setDaemon設置為True

main start

thread start

main end

  

從打印的結果可以看出,當設置為True的時候,線程還在sleep過程就就結束了,以至於thread end這句都沒有打印出來。

當然Thread類還不止這些方法,這些只是常用的方法,通過help(Thread)可以查看。

【python標準庫學習】thread,threading(一)多線程的介紹和使用