python關於線程管理的有2個類,_thread(在2.x的版本中叫thread)和threading。
# encoding: UTF-8 import thread import time # 一個用於在線程中執行的函數 def func(): for i in range(5): print 'func' time.sleep(1) # 結束當前線程 # 這個方法與thread.exit_thread()等價 thread.exit() # 當func返回時,線程同樣會結束 # 啟動一個線程,線程立即開始運行 # 這個方法與thread.start_new_thread()等價 # 第一個參數是方法,第二個參數是方法的參數 thread.start_new(func, ()) # 方法沒有參數時需要傳入空tuple # 創建一個鎖(LockType,不能直接實例化) # 這個方法與thread.allocate_lock()等價 lock = thread.allocate() # 判斷鎖是鎖定狀態還是釋放狀態 print lock.locked() # 鎖通常用於控制對共享資源的訪問 count = 0 # 獲得鎖,成功獲得鎖定后返回True # 可選的timeout參數不填時將一直阻塞直到獲得鎖定 # 否則超時后將返回False if lock.acquire(): count += 1 # 釋放鎖 lock.release() # thread模塊提供的線程都將在主線程結束后同時結束 time.sleep(6)
輸出:
Falsefunc
0
func 1
func 2
func 3
func 4
thread 模塊提供的其他方法:
thread.interrupt_main(): 在其他線程中終止主線程。
thread.get_ident(): 獲得一個代表當前線程的魔法數字,常用於從一個字典中獲得線程相關的數據。這個數字本身沒有任何含義,並且當線程結束后會被新線程復用。
thread還提供了一個ThreadLocal類用於管理線程相關的數據,名為 thread._local,threading中引用了這個類。
由於thread提供的線程功能不多,無法在主線程結束后繼續運行,不提供條件變量等等原因,一般不使用thread模塊,這里就不多介紹了。
python官網文檔:
This module provides low-level primitives for working with multiple threads (also called light-weight processes or tasks) — multiple threads of control sharing their global data space. For synchronization, simple locks (also called mutexes or binary semaphores) are provided. The threading module provides an easier to use and higher-level threading API built on top of this module.
The module is optional. It is supported on Windows, Linux, SGI IRIX, Solaris 2.x, as well as on systems that have a POSIX thread (a.k.a. “pthread”) implementation. For systems lacking the _thread module, the _dummy_thread module is available. It duplicates this module’s interface and can be used as a drop-in replacement.
It defines the following constant and functions:
- exception _thread. error
- Raised on thread-specific errors.
- _thread. LockType
- This is the type of lock objects.
- _thread. start_new_thread ( function, args [, kwargs ] )
- Start a new thread and return its identifier. The thread executes the function function with the argument list args (which must be a tuple). The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).
- _thread. interrupt_main ( )
- Raise a KeyboardInterrupt exception in the main thread. A subthread can use this function to interrupt the main thread.
- _thread. exit ( )
- Raise the SystemExit exception. When not caught, this will cause the thread to exit silently.
- _thread.allocate_lock()
- Return a new lock object. Methods of locks are described below. The lock is initially unlocked.
- _thread. get_ident ( )
- Return the ‘thread identifier’ of the current thread. This is a nonzero integer. Its value has no direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of thread-specific data. Thread identifiers may be recycled when a thread exits and another thread is created.
- _thread. stack_size ( [ size ] )
- Return the thread stack size used when creating new threads. The optional size argument specifies the stack size to be used for subsequently created threads, and must be 0 (use platform or configured default) or a positive integer value of at least 32,768 (32kB). If changing the thread stack size is unsupported, a ThreadError is raised. If the specified stack size is invalid, a ValueError is raised and the stack size is unmodified. 32kB is currently the minimum supported stack size value to guarantee sufficient stack space for the interpreter itself. Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32kB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4kB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific information). Availability: Windows, systems with POSIX threads.
Lock objects have the following methods:
- lock. acquire ( [ waitflag ] )
- Without the optional argument, this method acquires the lock unconditionally, if necessary waiting until it is released by another thread (only one thread at a time can acquire a lock — that’s their reason for existence). If the integer waitflag argument is present, the action depends on its value: if it is zero, the lock is only acquired if it can be acquired immediately without waiting, while if it is nonzero, the lock is acquired unconditionally as before. The return value is True if the lock is acquired successfully, False if not.
- lock. release ( )
- Releases the lock. The lock must have been acquired earlier, but not necessarily by the same thread.
- lock.locked()
- Return the status of the lock: True if it has been acquired by some thread, False if not.
In addition to these methods, lock objects can also be used via the with statement, e.g.:
import _thread
a_lock = _thread.allocate_lock()
with a_lock:
print("a_lock is locked while this executes")
Caveats:
-
Threads interact strangely with interrupts: the KeyboardInterrupt exception will be received by an arbitrary thread. (When thesignal module is available, interrupts always go to the main thread.)
-
Calling sys.exit() or raising the SystemExit exception is equivalent to calling _thread.exit().
-
Not all built-in functions that may block waiting for I/O allow other threads to run. (The most popular ones (time.sleep(),file.read(), select.select()) work as expected.)
-
It is not possible to interrupt the acquire() method on a lock — the KeyboardInterrupt exception will happen after the lock has been acquired.
-
When the main thread exits, it is system defined whether the other threads survive. On SGI IRIX using the native thread implementation, they survive. On most other systems, they are killed without executing try ... finally clauses or executing object destructors.
-
When the main thread exits, it does not do any of its usual cleanup (except that try ... finally clauses are honored), and the standard I/O files are not flushed.
轉自:http://docs.python.org/3.1/library/_thread.html
------------------------------------------------------------------------------------------------------------------------
python中的多線程
Python中實現多線程有兩種方式,一種基於_thread模塊(在Python2.x版本中為thread模塊,沒有下划線)的start_new_thread()函數,另一種基於threading模塊的Thread類。
其實Python的多線程編程不能真正利用多核的CPU,但是用開源模塊使你的計算壓力分布到多核CPU上.........
一.使用start_new_thread()實現線程,是比較底層的實現方式,所有線程共享他們global數據,為了達到同步,模塊也提供了簡單的鎖機制
_thread.start_new_thread(function, args[, kwargs]) |
啟動一個新的進程,並返回其標識符. 線程執行的函數需要的參數由args(必須為一個元組)提供,亦可通過可選參數kwargs提供關鍵字參數組 成的字典。當函數返回時,啟動的線程也 停止退出。如果函數中存在未處理異常,會打印堆棧跟蹤后線程停止退出(其他線程繼續執行)。 |
其中線程標識符是一個非0整數,並沒有直接意思,可以當作從一個線程組成的特殊字典中索引本線程的一個key,也可用_thread.get_ident()得到,在線程退出后,標識符會被系統回收。在線程執行過程中可以調用_thread.exit()終止本線程的執行。
import _thread import time def threadFunction(count): for i in range(count): print('進程id為%d的打印%d'%(_thread.get_ident(),i)) i-=1 time.sleep(0.1) def begin(): ident1=_thread.start_new_thread(threadFunction,(100,)) print('啟動標識符為%d的進程'%(ident1,)) ident2=_thread.start_new_thread(threadFunction,(100,)) print('啟動標識符為%d的進程'%(ident2,)) if __name__ == '__main__': begin()
二.使用Thread類來實現多線程,這種方式是對_thread模塊(如果沒有_thread,則為dummy_threading)的高級封裝,在這種方式下我們需創建新類繼承threading.Thread,和java一樣重寫threading.Thread的run方法即可.啟動線程用線程的start方法,它會調用我們重寫的run方法.
class MyThread(threading.Thread): '''只能重寫__init__ 和 run 兩個方法''' def __init__(self,name): threading.Thread.__init__(self) self.name=name self.bool_stop=False def run(self): while not self.bool_stop: print('進程%s,於%s'%(self.name,time.asctime())) time.sleep(1) def stop(self): self.bool_stop = True if __name__ == '__main__': th1=MyThread('one') th2=MyThread('two') th1.start() th2.start()
Thread類還定義了以下常用方法與屬性:
Thread.getName() \Thread.setName() |
老方式用於獲取和設置線程的名稱,官方建議用Thread.name替代 |
Thread.ident |
獲取線程的標識符。只有在調用start()方法執行后才有效,否則返回None。 |
Thread.is_alive() |
判斷線程是否是激活的。 |
Thread.join([timeout]) |
調用Thread.join將會使主調線程堵塞,直到被調用線程運行結束或超時。參數timeout是一個數值類型,表示超時時間,如果未提供該參數,那么主調線程將一直堵塞到被調線程結束。 |
Python中的鎖
先用_thread模塊的Lock鎖來實現生產者消費者問題,Lock對象是Python提供的低級線程控制工具,使用起來非常簡單,只需下面3條語句即可:
_thread.allocate_lock()返回一個新Lock對象,即為一個新鎖 |
lock.acquire() 相當於P操作,得到一個鎖, |
lock.release()相當於V操作,釋放一個鎖 |
代碼如下:
import _thread,time,random dish=0 lock = _thread.allocate_lock() def producerFunction(): '''如果投的篩子比0.2大,則向盤子中增加一個蘋果''' global lock,dish while True: if(random.random() > 0.1): lock.acquire() if dish < 100: dish+=1 print('生產者增加了一個蘋果,現在有%d個蘋果'%(dish,)) lock.release() time.sleep(random.random()*3) def consumerFunction(): '''如果投的篩子比0.5大,則從盤子中取一個蘋果''' global lock,dish while True: if(random.random() > 0.9): lock.acquire() if dish > 0: dish-=1 print('消費者拿走一個蘋果現,在有%d個蘋果'%(dish,)) lock.release() time.sleep(random.random()*3) def begin(): ident1=_thread.start_new_thread(producerFunction,()) ident2=_thread.start_new_thread(consumerFunction,()) if __name__ == '__main__': begin()
另一個較高級的鎖為RLock鎖,RLock對象內部維護着一個Lock對象,它是一種可重入的對象。對於Lock對象而言,如果一個線程連續兩次進行acquire操作,那么由於第一次acquire之后沒有release,第二次acquire將掛起線程。這會導致Lock對象永遠不會release,使得線程死鎖。RLock對象允許一個線程多次對其進行acquire操作,因為在其內部通過一個counter變量維護着線程acquire的次數。而且每一次的acquire操作必須有一個release操作與之對應,在所有的release操作完成之后,別的線程才能申請該RLock對象。
threading模塊對Lock也提供和封裝,提供了更高級的同步方式(可以理解為更高級的鎖),包括threading.Event和threading.Condition,其中threading.Event為提供了簡單的同步方式:一個進程標記event,其他進程等待,只需下面的幾個方法即可:
Event.wait([timeout]) |
堵塞線程,直到Event對象內部標識位被設為True或超時(如果提供了參數timeout)。 |
Event.set() |
將標識號設為Ture |
Event.clear() |
設為標識符False |
threading.Condition 可以把Condiftion理解為一把高級的瑣,它提供了比Lock, RLock更高級的功能,允許我們能夠控制復雜的線程同步問題。threadiong.Condition在內部維護一個瑣對象(默認是RLock),可以在創建Condigtion對象的時候把瑣對象作為參數傳入。Condition也提供了acquire, release方法,其含義與瑣的acquire, release方法一致,其實它只是簡單的調用內部瑣對象的對應的方法而已。Condition還提供了如下方法(特別要注意:這些方法只有在占用瑣(acquire)之后才能調用,否則將會報RuntimeError異常。):
Condition.wait([timeout]): |
wait方法釋放內部所占用的瑣,同時線程被掛起,直至接收到通知被喚醒或超時(如果提供了timeout參數的話)。當線程被喚醒並重新占有瑣的時候,程序才會繼續執行下去。 |
Condition.notify(): |
喚醒一個掛起的線程(如果存在掛起的線程)。注意:notify()方法不會釋放所占用的瑣。 |
Condition.notify_all() |
喚醒所有掛起的線程(如果存在掛起的線程)。注意:這些方法不會釋放所占用的瑣。 |
更多:
http://www.freeloong.net/20130623745.html
http://www.ibm.com/developerworks/cn/aix/library/au-threadingpython/
http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html 很好的文章