一 线程简介
说道python线程,其封装和方法也比较多样,使用比较方便。目前主要的有三种方式。
1.1
方法一:通过使用thread模块中的函数创建新线程。
但是注意在3.4版本里面,该函数已经不再thread模块之中,若要引用需要导入
import _dummy_thread.其函数实现源码为:
def start_new_thread(function, args, kwargs={}): """Dummy implementation of _thread.start_new_thread(). Compatibility is maintained by making sure that ``args`` is a tuple and ``kwargs`` is a dictionary. If an exception is raised and it is SystemExit (which can be done by _thread.exit()) it is caught and nothing is done; all other exceptions are printed out by using traceback.print_exc(). If the executed function calls interrupt_main the KeyboardInterrupt will be raised when the function returns. """ if type(args) != type(tuple()): raise TypeError("2nd arg must be a tuple") if type(kwargs) != type(dict()): raise TypeError("3rd arg must be a dict") global _main _main = False try: function(*args, **kwargs) except SystemExit: pass except: import traceback traceback.print_exc() _main = True global _interrupt if _interrupt: _interrupt = False raise KeyboardInterrupt
使用的时候比如:
def run(n): for i in range(n): print (i) _dummy_thread.start_new_thread (run, (4,)) # 注意第二个参数一定要是元组的形式
1.2
方法二:使用threading.Thread直接在线程中运行函数。
class Thread: """A class that represents a thread of control. This class can be safely subclassed in a limited fashion. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass #...................... def is_alive(self):#该函数返回当前线程是否存活状态,比较重要。 #Return whether the thread is alive. def ident(self):#该函数返回当前线程的ID标示符,类似于TID #Thread identifier of this thread or None if it has not been started. This is a nonzero integer. def run(self):#该函数是线程的运行函数,可以自己覆盖重写,也可以直接进行默认调用。 #Method representing the thread's activity. def start(self):#线程启动函数,创建的线程自己不会启动,必须自己手动启动。 #Start the thread's activity. def join(self, timeout=None):#该函数实现等待到运行结束,类似于同步也叫线程合并,因为join之后线程结束 #才运行下一行代码,待会代码实例测试。 #Wait until the thread terminates. def _wait_for_tstate_lock(self, block=True, timeout=-1):#线程自身带了互斥锁 def setDaemon(self):#设置线程属性状态,若果设置为True主线程结束,子线程就被主线程结束, #若是False则必须等待到所有子线程结束,主线程才结束退出。
import threading def running(x, y): for i in range(x, y): print (i) for i in range(3): t1 = threading.Thread(target=running, args=(1 * i, 10 * (i + 1))) t1.start() t1.join()采用join方法结果
0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29若不采用则线程竞争出现毫无规律数字,甚至出现重复,因为这里没有进行互斥
0 1 1 2 3 4 5 6 7 8 9 2 2 3 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
1.3
方法三:通过继承threading.Thread创建线程
class mz_thread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): while True: print ('I am', self.num) for i in range(10): t = mz_thread(i) t.start()
I am 9 I am 0 I am 8 I am 1 I am 6 I am 7 I am 5 I am 2 I am 4 I am 9 I am 4 I am 9 I am 0 I am 8 I am 1 I am 6 I am 3 I am 7 I am 5 I am 2 I am 4 I am 9 I am 0 I am 8 I am 7 I am 5 I am 2 I am 4 I am 9 I am 0 I am 8 I am 1 I am 6 I am 3 I am 7 I am 7 I am 5 I am 2 I am 4 I am 9
二 利用EVENT类的实现线程之间同步
首先看看Event类的定义代码
class Event: """Class implementing event objects. Events manage a flag that can be set to true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true. The flag is initially false. """ # After Tim Peters' event class (without is_posted()) def __init__(self): self._cond = Condition(Lock()) self._flag = False #很关键默认创建之后信号状态为False def _reset_internal_locks(self): # private! called by Thread._reset_internal_locks by _after_fork() self._cond.__init__() def is_set(self):#很关键,获取当前事件信号状态,返回值为True和False """Return true if and only if the internal flag is true.""" return self._flag isSet = is_set def set(self):#很关键,将事件信号设置为有信号状态 """Set the internal flag to true. All threads waiting for it to become true are awakened. Threads that call wait() once the flag is true will not block at all. """ self._cond.acquire() try: self._flag = True self._cond.notify_all() finally: self._cond.release() def clear(self):#很关键,将事件信号设置为无信号状态 """Reset the internal flag to false. Subsequently, threads calling wait() will block until set() is called to set the internal flag to true again. """ self._cond.acquire() try: self._flag = False finally: self._cond.release() def wait(self, timeout=None):#很关键,进行同步信号等待函数 """Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs. When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). This method returns the internal flag on exit, so it will always return True except if a timeout is given and the operation times out. """ self._cond.acquire() try: signaled = self._flag if not signaled: signaled = self._cond.wait(timeout) return signaled finally: self._cond.release()//使用event进行同步,那么必须在多线程下,同时也得创建多个event对象数组。
注意这里python数组这样定义和动态创建。
INT_EVENTS_LIST = [] for i in range(3): INT_EVENTS_LIST.append(threading.Event()) INT_EVENTS_LIST[0].set()#调用的时候也是采用下标索引方式实现。测试同步代码
class mz_thread(threading.Thread): m_Src = 0 m_Des = 0 m_iIndex = 0 def __init__(self, numSrc, numDes, iIndex): threading.Thread.__init__(self) self.m_Src = numSrc self.m_Des = numDes self.m_iIndex = iIndex def run(self): while self.m_Src < self.m_Des: INT_EVENTS_LIST[self.m_iIndex].wait() print ('I am thread ', self.m_iIndex, '--Num--', self.m_Src) INT_EVENTS_LIST[self.m_iIndex].clear() INT_EVENTS_LIST[(self.m_iIndex + 1) % 3].set() INT_EVENTS_LIST = [] THREAD_ARRAY = [] if __name__ == '__main__': print('Main Thread Run :', __name__) for i in range(3): INT_EVENTS_LIST.append(threading.Event()) INT_EVENTS_LIST[0].set() for iThreadIndex in range(3): THREAD_ARRAY.append(mz_thread(iThreadIndex * 3, (iThreadIndex + 1) * 3, iThreadIndex)) THREAD_ARRAY[iThreadIndex].start()
I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6 I am thread 0 --Num-- 0 I am thread 1 --Num-- 3 I am thread 2 --Num-- 6三 说明
在Python里面同步的方式除了使用Event事件也可以直接使用Queue队列。因为
Python队列Queue操作本身进行了原语封装,实现了同步访问。也可以自定义标志
或者相关变量来访问。至于线程互斥那方法就更多了。下一节将会学习。