目前,对于管理并发性,软件应用中使用最广泛的编程模型就是基于多线程。通常,应用包括一个进程,这个进程可以划分为多个独立的线程,分别表示并运行的不同类型的活动。这些线程会相互竞争。 如今,使用多线程的现代应用已经得到大规模使用。本文介绍python中的threading库实现基于线程的并发。
一、什么是线程
? 线程是一个独立的执行流,可以与系统中的其它线程并发地执行。
? 多个线程可以共享数据和资源,充分利用共享信息空间。一般来讲,可以说线程包含在一个进程中,同一个进程中的不同线程会共享一些资源。
? 线程由3个元素组成:程序计数器、寄存器和堆栈。与相同进程中的其它线程共享的资源基本上包括数据和操作系统资源。另外,线程由自己的执行状态,也就是线程状态,而且可以与其它线程同步。
? 线程状态可以是就绪、运行或阻塞。
二、Python threading模块
? Python用Python标准库提供threading模块管理线程。这个模块提供了一些非常有意思的特性,使基于线程的方法变得容易得多。
1. threading模块的主要组件包括:
thread 对象lock 对象RLock 对象semaphore 对象condition 对象event 对象
2. 定义一个线程
? 使用线程最简单的方法是用一个目标函数实例化线程,然后调用start方法让它开始工作。
? Python的threading模块提供了了一个Thread类,用来在一个不同的线程中运行方法和函数:
class threading.Thread(group=None,
target=None,
name=None,
args=(),
kwargs={}
)
? 参数说明:
group : 这是线程组值,必须为None;这是为将来的实现保留。target : 这是启动一个线程活动时要执行的目标函数。name :这是线程名。默认地,会为线程指定一个唯一的线程名。args : 这是要传递到目标函数的参数元组。kwargs : 这是用于target 函数的关键字参数字典。
3.实现过程
import threading
t = threading.Thread(target=funtion, args=(i,))
t.start()
t.join()
调用start方法之前这个线程不会开始运行,join方法会让调用的线程(即主线程)等待,直到这个线程完成执行。
4.定义一个线程子类
? 创建一个线程要求定义一个继承Thread类的子类。示例:
import threading
import os
import time
from threading import Thread
class MyThread(Thread):
def __init__(self, name, duration_):
Thread.__init__(self)
self.name = name
self.duration = duration_
def run(self) -> None:
print("——>"+self.name+" running, belonging to process ID"+str(os.getpid()))
time.sleep(self.duration)
print(f"{self.name} is over!")
if __name__ == '__main__':
duration = 3
start = time.time()
thread1 = MyThread("Thread#1", duration)
thread2 = MyThread("Thread#2", duration)
thread3 = MyThread("Thread#3", duration)
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
print("#End!")
print("——%s seconds ——" % (time.time()-start))
输出:
——>Thread#1 running, belonging to process ID7200
——>Thread#2 running, belonging to process ID7200
——>Thread#3 running, belonging to process ID7200
Thread#1 is over!
Thread#3 is over!
Thread#2 is over!
#End!
——3.0039620399475098 seconds ——
进程已结束,退出代码为 0
按照顺序编程,该程序至少需要在9s 内完成,使用并发可在3s 左右运行完。
三、使用锁的线程同步
? 锁(lock)就是通常可以由多个线程访问的一个对象,一个线程在进行执行程序的一个保护区之前,必须拥有锁。这些锁通过执行Lock() 方法创建。
? 一旦创建了锁,可以使用两个方法来同步两个(或更多)线程的执行:acquire() 方法获得锁控制和release() 方法释放锁。
? 下面通过锁的不同位置体现使用锁的线程同步:
? (1)在一个线程的中间位置
import threading
import os
import time
from threading import Thread
threadLock = threading.Lock()
class MyThread(Thread):
def __init__(self, name, duration_):
Thread.__init__(self)
self.name = name
self.duration = duration_
def run(self) -> None:
threadLock.acquire()
print("——>"+self.name+" running, belonging to process ID"+str(os.getpid()))
threadLock.release()
time.sleep(self.duration)
print(f"{self.name} is over!")
if __name__ == '__main__':
duration = 3
start = time.time()
thread1 = MyThread("Thread#1", duration)
thread2 = MyThread("Thread#2", duration)
thread3 = MyThread("Thread#3", duration)
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
print("#End!")
print("——%s seconds ——" % (time.time()-start))
输出
——>Thread#1 running, belonging to process ID9768
——>Thread#2 running, belonging to process ID9768
——>Thread#3 running, belonging to process ID9768
Thread#1 is over!Thread#2 is over!Thread#3 is over!
#End!
——3.0111279487609863 seconds ——
进程已结束,退出代码为 0
? 锁的获得和释放之间的部分程序先后执行,其它部分并发执行。
(2)锁在线程的开始和结束部分
import threading
import os
import time
from threading import Thread
threadLock = threading.Lock()
class MyThread(Thread):
def __init__(self, name, duration_):
Thread.__init__(self)
self.name = name
self.duration = duration_
def run(self) -> None:
threadLock.acquire()
print("——>"+self.name+" running, belonging to process ID"+str(os.getpid()))
time.sleep(self.duration)
print(f"{self.name} is over!")
threadLock.release()
if __name__ == '__main__':
duration = 3
start = time.time()
thread1 = MyThread("Thread#1", duration)
thread2 = MyThread("Thread#2", duration)
thread3 = MyThread("Thread#3", duration)
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()
print("#End!")
print("——%s seconds ——" % (time.time()-start))
输出
——>Thread#1 running, belonging to process ID4908
Thread#1 is over!
——>Thread#2 running, belonging to process ID4908
Thread#2 is over!
——>Thread#3 running, belonging to process ID4908
Thread#3 is over!
#End!
——9.013749837875366 seconds ——
进程已结束,退出代码为 0
` ——>Thread#1 running, belonging to process ID4908 Thread#1 is over! ——>Thread#2 running, belonging to process ID4908 Thread#2 is over! ——>Thread#3 running, belonging to process ID4908 Thread#3 is over! #End! ——9.013749837875366 seconds ——
进程已结束,退出代码为 0
线程会按顺序执行。
|