每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
线程可以分为:
Python3 线程中常用的两个模块为:
调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下:
_thread.start_new_thread?(?function,?args[,?kwargs]?)
参数说明:
import?_thread,?time
#?定义线程函数
def?print_time(threadName,?delay):
???count?=?0
???while?count?<?5:
???????time.sleep(delay)
???????count?+=?1
???????#?返回当前时间的时间戳(1970纪元后经过的浮点秒数),?并格式化输出
???????print("{}:?{}".format(threadName,?time.ctime(time.time())?))
try:
???_thread.start_new_thread(?print_time,?("Thread-1",?2))
???_thread.start_new_thread(?print_time,?("Thread-2",?4))
except:
???print("Error")
while?1:
???#?让线程有足够的时间完成
???pass
E:\PyPro>python?thread.py
Thread-1:?Thu?Apr?12?09:01:56?2018
Thread-2:?Thu?Apr?12?09:01:58?2018
Thread-1:?Thu?Apr?12?09:01:58?2018
Thread-1:?Thu?Apr?12?09:02:00?2018
Thread-2:?Thu?Apr?12?09:02:02?2018
Thread-1:?Thu?Apr?12?09:02:02?2018
Thread-1:?Thu?Apr?12?09:02:05?2018
Thread-2:?Thu?Apr?12?09:02:06?2018
Thread-2:?Thu?Apr?12?09:02:10?2018
Thread-2:?Thu?Apr?12?09:02:14?2018
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:
线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
import?threading,?time
#?创建进程类
class?myThread(threading.Thread):
???#?构造函数
???def?__init__(self,?threadID,?name,?counter):
???????threading.Thread.__init__(self)
???????self.threadID?=?threadID
???????self.name?=?name
???????self.counter?=?counter
???#?重写run()
???def?run(self):
???????print("Thread?Strat:"?+?self.name)
???????print_time(self.name,?self.counter,?5)
???????print("Thread?Exit:"?+?self.name)
???????
def?print_time(threadName,?delay,?counter):
???while?counter:
???????time.sleep(delay)
???????print("{}:?{}".format(threadName,?time.ctime(time.time())?))
???????counter?-=?1????
#?创建线程
thread1?=?myThread(1001,?"Thread-1",?1)
thread2?=?myThread(1002,?"Thread-2",?2)
#?开启线程
print("Thread-1?is?Alive??",?thread1.isAlive())
thread1.start()
thread2.start()
print("Thread-1?is?Alive??",?thread1.isAlive())
thread1.join()
thread2.join()
print("Thread-1?is?Alive??",?thread1.isAlive())
print("exit")
E:\PyPro>python?threadClass.py
Thread-1?is?Alive???False
Thread?Strat:Thread-1
Thread?Strat:Thread-2
Thread-1?is?Alive???True
Thread-1:?Thu?Apr?12?10:15:53?2018
Thread-1:?Thu?Apr?12?10:15:54?2018
Thread-2:?Thu?Apr?12?10:15:54?2018
Thread-1:?Thu?Apr?12?10:15:55?2018
Thread-1:?Thu?Apr?12?10:15:56?2018
Thread-2:?Thu?Apr?12?10:15:56?2018
Thread-1:?Thu?Apr?12?10:15:57?2018
Thread?Exit:Thread-1
Thread-2:?Thu?Apr?12?10:15:58?2018
Thread-2:?Thu?Apr?12?10:16:00?2018
Thread-2:?Thu?Apr?12?10:16:02?2018
Thread?Exit:Thread-2
Thread-1?is?Alive???False
exit
不难发现,线程是通过start()函数激活,而不是对象建立时激活的!
多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
import?threading,?time
#?创建锁
threadLock?=?threading.Lock()
#?创建线程列表
threads?=?[]
class?myThread(threading.Thread):
???def?__init__(self,?threadID,?name,?counter):
???????threading.Thread.__init__(self)
???????self.threadID?=?threadID
???????self.name?=?name
???????self.counter?=?counter
???
???def?run(self):
???????print("Thread?Start:?"?+?self.name)
???????#?获取锁,同步线程
???????threadLock.acquire()
???????print_time(self.name,?self.counter,?3)
???????#?释放锁,开启下一个线程
???????threadLock.release()
???????print("Thread?Exit:?"?+?self.name)
???????
def?print_time(threadName,?delay,?counter):
???while?counter:
???????time.sleep(delay)
???????print("{}:?{}".format(threadName,?time.ctime()))
???????counter?-=?1
???????
#?创建线程
thread1?=?myThread(1001,?"Thread-1",?1)
thread2?=?myThread(1002,?"Thread-2",?2)
#?开启线程
thread1.start()
thread2.start()
#?添加线程列表
threads.append(thread1)
threads.append(thread2)
#?等待所有线程完成
for?t?in?threads:
???t.join()
print("exit")
E:\PyPro>python?synchronize.py
Thread?Start:?Thread-1
Thread?Start:?Thread-2
Thread-1:?Thu?Apr?12?11:00:49?2018
Thread-1:?Thu?Apr?12?11:00:50?2018
Thread-1:?Thu?Apr?12?11:00:51?2018
Thread?Exit:?Thread-1
Thread-2:?Thu?Apr?12?11:00:53?2018
Thread-2:?Thu?Apr?12?11:00:55?2018
Thread-2:?Thu?Apr?12?11:00:57?2018
Thread?Exit:?Thread-2
exit
Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO队列Queue,LIFO队列LifoQueue,和优先级队列 PriorityQueue。
这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。
Queue 模块中的常用方法:
import?queue,?threading,?time
exitFlag?=?0
#?创建锁
queueLock?=?threading.Lock()
#?创建队列
workQueue?=?queue.Queue(10)
class?myThread(threading.Thread):
???def?__init__(self,?threadID,?name,?q):
???????threading.Thread.__init__(self)
???????self.threadID?=?threadID
???????self.name?=?name
???????self.q?=?q
???????
???def?run(self):
???????print("Thread?Start:?"?+?self.name)
???????process_data(self.name,?self.q)
???????print("Thread?Exit:?"?+?self.name)
???????
def?process_data(threadName,?q):
???while?not?exitFlag:
???????queueLock.acquire()
???????if?not?workQueue.empty():
???????????data?=?q.get()
???????????queueLock.release()
???????????print("{}?processing?{}".format(threadName,?data))
???????else:
???????????queueLock.release()
???????time.sleep(1)
threadList?=?["Thread-1",?"Thread-2",?"Thread-3"]
nameList?=?["One",?"Two",?"Three",?"Four",?"Five"]
threads?=?[]
threadID?=?1
#?创建新线程
for?tName?in?threadList:
???thread?=?myThread(threadID,?tName,?workQueue)
???thread.start()
???threads.append(thread)
???threadID?+=?1
#?填充队列
queueLock.acquire()
print("队列填充中>>>>>>>>>>>>>>")
time.sleep(1)
for?word?in?nameList:
???workQueue.put(word)
print("队列填充完毕>>>>>>>>>>>>>>")
queueLock.release()
#?等待队列清空
while?not?workQueue.empty():
???pass
#?通知线程退出
exitFlag?=?1
#?等待所有线程完成
for?t?in?threads:
???t.join()
print("exit")
E:\PyPro>python?queueue.py
Thread?Start:?Thread-1
Thread?Start:?Thread-2
Thread?Start:?Thread-3
队列填充中>>>>>>>>>>>>>>
队列填充完毕>>>>>>>>>>>>>>
Thread-3?processing?One
Thread-1?processing?Two
Thread-2?processing?Three
Thread-3?processing?Four
Thread-1?processing?Five
Thread?Exit:?Thread-2
Thread?Exit:?Thread-1
Thread?Exit:?Thread-3
exit
源码中其实实现了三个进程读取同一个队列,按照先进先出原则实现锁定。
用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
join的作用是保证当前线程执行完成后,再执行其它线程。join可以有timeout参数,表示阻塞其它线程timeout秒后,不再阻塞。。一般线程的start()之后,所有操作结束后都要进行thread.join()。确保语句的输出是join()后面的
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。