Python 3 -多线程编程
运行多个线程类似于同时运行几个不同的程序,但具有以下优点:
- 进程内的多个线程与主线程共享相同的数据空间,因此比分离进程更容易共享信息或相互通信。
-
线程有时被称为轻型进程,它们不需要太多的内存开销;它们比进程更便宜。
线程具有开始、执行顺序和结束。它有一个指令指针,用于跟踪它当前正在运行的位置。
- 它可以被抢占(中断)。
-
它可以被临时放置在保留状态(也称为休眠),而其他线程正在运行时-这称为让步。
有两种不同类型的线程-
- 内核线程
-
用户线程
内核线程是操作系统的一部分,而用户空间线程在内核中没有实现。
有两个模块支持在Python3中使用线程-
_thread
threading
线程模块已经“被废弃”很长时间了。鼓励用户使用线程模块。因此,在Python 3中,模块“thread”不再可用。但是,为了向后兼容性,在Python3中将其重命名为“_thread”。
启动新线程
要生成另一个线程,您需要调用 thread 模块中提供的以下方法-
_thread.start_new_thread ( function, args[, kwargs] )
此方法调用在Linux和Windows中均可快速有效地创建新线程。该方法调用立即返回,子线程启动并使用传递的 args 列表调用函数。当函数返回时,线程终止。
在这里, args 是参数元组;使用一个空元组调用不传递任何参数的函数。 kwargs 是可选的关键字参数字典。
示例
#!/usr/bin/python3
import _thread
import time
# 定义线程函数
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print ("%s: %s" % ( 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: unable to start thread")
while 1:
pass
输出
当执行以上代码时,它会产生以下结果-
Thread-1: Fri Feb 19 09:41:39 2016
Thread-2: Fri Feb 19 09:41:41 2016
Thread-1: Fri Feb 19 09:41:41 2016
Thread-1: Fri Feb 19 09:41:43 2016
Thread-2: Fri Feb 19 09:41:45 2016
Thread-1: Fri Feb 19 09:41:45 2016
Thread-1: Fri Feb 19 09:41:47 2016
Thread-2: Fri Feb 19 09:41:49 2016
Thread-2: Fri Feb 19 09:41:53 2016
程序进入无限循环。您必须按ctrl-c停止
虽然 thread 模块非常适用于低级线程,但与较新的线程模块相比,它非常有限。
线程模块
Python 2.4附带的较新的线程模块比前一节讨论的线程模块提供了更强大的高级线程支持。
threading 模块公开了 thread 模块的所有方法,并提供了一些附加方法-
- threading.activeCount() − 返回当前活动的线程数。
-
threading.currentThread() − 返回调用线程控制中的线程数。
-
threading.enumerate() − 返回所有当前活动的线程对象列表。
除了这些方法,threading模块还有一个 Thread 类来实现线程,该类提供的方法如下 −
- run() − run()方法是线程的入口点。
-
start() − start()方法通过调用run方法启动一个线程。
-
join([time]) − join()方法等待线程终止。
-
isAlive() − isAlive()方法检查线程是否在执行。
-
getName() − getName()方法返回线程的名称。
-
setName() − setName()方法设置线程的名称。
使用Threading模块创建线程
要使用threading模块实现新线程,您需要执行以下操作 −
- 定义 Thread 类的新子类。
-
重写 init(self [,args]) 方法以添加其他参数。
-
然后,重写run(self [,args])方法以实现线程开始时的操作。
创建了新的 Thread 子类之后,您可以创建其实例,然后通过调用 start() 开启新线程,该方法随后调用 run() 方法。
例子
#!/usr/bin/python3
import threading
import time
exitFlag = 0
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 ("Starting " + self.name)
print_time(self.name, self.counter, 5)
print ("Exiting " + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")
结果
运行上述程序会产生以下结果−
Starting Thread-1
Starting Thread-2
Thread-1: Fri Feb 19 10:00:21 2016
Thread-2: Fri Feb 19 10:00:22 2016
Thread-1: Fri Feb 19 10:00:22 2016
Thread-1: Fri Feb 19 10:00:23 2016
Thread-2: Fri Feb 19 10:00:24 2016
Thread-1: Fri Feb 19 10:00:24 2016
Thread-1: Fri Feb 19 10:00:25 2016
Exiting Thread-1
Thread-2: Fri Feb 19 10:00:26 2016
Thread-2: Fri Feb 19 10:00:28 2016
Thread-2: Fri Feb 19 10:00:30 2016
Exiting Thread-2
Exiting Main Thread
同步线程
Python提供的threading模块包括一个简单的可实现锁定机制,允许您同步线程。通过调用 Lock() 方法来创建新的锁对象,它返回新的锁对象。
新的锁对象的 acquire(blocking) 方法用于强制线程同步运行。可选的 blocking 参数使您可以控制线程是否等待获取锁。
如果设置 blocking 为0,则如果无法获得锁,则线程立即返回0,如果获得锁,则返回1。如果设置blocking为1,则线程阻塞并等待锁被释放。
当不再需要锁时,使用新的锁对象的 release() 方法释放锁。
示例
#!/usr/bin/python3
import threading
import time
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 ("Starting " + self.name)
# Get lock to synchronize threads
threadLock.acquire()
print_time(self.name, self.counter, 3)
# Free lock to release next thread
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
threadLock = threading.Lock()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
# Add threads to thread list
threads.append(thread1)
threads.append(thread2)
# Wait for all threads to complete
for t in threads:
t.join()
print ("Exiting Main Thread")
输出
执行上述代码时,会产生以下结果−
Starting Thread-1
Starting Thread-2
Thread-1: Fri Feb 19 10:04:14 2016
Thread-1: Fri Feb 19 10:04:15 2016
Thread-1: Fri Feb 19 10:04:16 2016
Thread-2: Fri Feb 19 10:04:18 2016
Thread-2: Fri Feb 19 10:04:20 2016
Thread-2: Fri Feb 19 10:04:22 2016
Exiting Main Thread
多线程优先队列
Queue 模块允许您创建一个新队列对象,该对象可以保存指定数量的项目。有以下方法来控制队列−
- get() − get() 从队列中删除并返回一个项目。
-
put() − put添加项目到一个队列中。
-
qsize() − qsize() 返回当前在队列中的项目数。
-
empty() − empty() 如果队列为空,则返回True;否则,False。
-
full() − full() 如果队列已满,则返回True;否则,False。
示例
#!/usr/bin/python3
import queue
import threading
import time
exitFlag = 0
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 ("Starting " + self.name)
process_data(self.name, self.q)
print ("Exiting " + self.name)
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print ("%s processing %s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
# Create new threads
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# Fill the queue
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# Wait for queue to empty
while not workQueue.empty():
pass
# Notify threads it's time to exit
exitFlag = 1
# Wait for all threads to complete
for t in threads:
t.join()
print ("Exiting Main Thread")
输出
执行上述代码后,将产生以下结果 −
Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 处理 One
Thread-2 处理 Two
Thread-3 处理 Three
Thread-1 处理 Four
Thread-2 处理 Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread