Python多线程模块Threading用法详解与示例
本文深入解析Python中Threading模块的使用方法,清晰区分进程与线程的概念及区别。通过继承Thread类和直接实例化Thread对象两种途径,结合完整代码示例,演示多线程在Python中的具体实现与资源同步技巧,帮助开发者掌握并发编程核心知识。
本文详细介绍Python多线程模块Threading的具体用法,旨在为读者提供实用的参考代码与理论解析。
在深入具体代码之前,有必要先厘线程与进程的基础概念。
对于测试人员而言,仅从理论层面理解两者的概念或区别可能较为抽象,因此这里通过一个生活化的例子来阐释相关概念。
以平安夜收到苹果或香蕉为例:当你用手接住对方递来的苹果时,你的手臂可以比喻为进程,而你的五根手指则比喻为线程。由此可见,线程是进程的细化,没有进程就不会有线程。
接下来阐述几个必要的核心概念:
进程
进程是操作系统中当前程序的一次执行实例。尽管拥有单个CPU的电脑在严格意义上同一时刻只能执行一个工作命令,但由于计算机运行速度极快,系统可以在A代码和B代码之间快速交错执行。这种高速切换使得用户感觉多个程序在同时进行,这就是多进程的原理。
线程
线程是程序内部一个单一的顺序控制流程,是进程内相对独立且可调度的执行单元,也是系统独立调度和分配CPU的基本单位。在单个程序中同时运行多个线程以完成不同工作,称为多线程。线程支持自行创建、撤销和切换。延续前面的例子,如果一根手指就能完成拿苹果的动作,即为单线程;若需要多根手指协作,则为多线程。
进程和线程的区别
(1)进程是资源分配和调度的独立单元,而线程是CPU调度的基本单元。 (2)同一进程内可包含多个线程,线程共享进程的大部分资源(如寄存器、堆栈、上下文),但一个进程至少包含一个线程。 (3)进程结束时,其拥有的所有线程均会被销毁;而线程的结束不会影响同一进程中其他线程的运行。 (4)线程是轻量级进程,其创建和销毁耗时远少于进程,因此操作系统中的执行功能通常通过创建线程来完成。 (5)线程执行时通常需要进行同步和互斥操作,因为它们共享同一进程的所有资源,存在资源竞争。 (6)线程拥有私有属性TCB(包括线程ID、寄存器、硬件上下文),进程拥有私有属性PCB(进程控制块),这些私有属性不共享,用于标识进程或线程。
子进程与子线程的区别
进程与线程的主要区别在于粒度:进程间的变量或内存不能直接互相访问,而线程可以,且线程必须依附于某个进程执行。举例来说,在Windows下打开一个IE浏览器,该浏览器是一个进程。当使用浏览器打开PDF文件时,IE调用Acrobat软件,此时Acrobat是一个独立的进程,即IE的子进程。而IE自身在同一进程中打开两个网页并同时运行脚本,这是通过IE内部的两个线程实现的。值得注意的是,线程仍属于IE的一部分,而子进程Acrobat严格来说不属于IE,而是另一个程序,之所以称为子进程,仅是因为受IE调用而启动。
读者可能会疑惑进程分配内存空间的依据。实际上,进程建立时,系统会为其分配虚拟地址空间(在32位系统中通常为4GB),具体分配情况取决于该进程包含的所有可执行模块或DLL模块的代码和数据,以及动态内存分配的空间(如线程中堆栈的分配)。
上述内容介绍了基本的线程及进程概念,接下来进入正题,主要总结Python中Threading模块的使用。
Python多线程之Threading
单线程
单线程处理类似于操作系统的单任务模式,即按顺序排队执行,依次处理。
多线程
Python中实现多线程Threading通常有两种方式:一是继承Thread类并重写其run方法;二是创建threading.Thread对象,在初始化函数(__init__)中将可调用对象作为参数传入。从本质上看,这两种方式是一致的。
以下是具体代码示例:
# -*- coding: utf-8 -*-
import threading
import time
#方式二是方式一的具体,方式一为类构造,方式二为方法实例构造,其实本质都是一样,都是调用threading.Thread模块
#方式一
count = 0
class Counter(threading.Thread):
def __init__(self, lock, threadName):
#注意:一定要显式的调用父类的初始化函数,这里可以指定生成的线程名,可以是*args、**kwargs
#def __init__(self, group=None, target=None, name=None, args=(), kwargs={}),其中group是预留的,将来用于扩展
super(Counter, self).__init__(name=threadName)
self.lock = lock
def run(self):
global count
self.lock.acquire()
for i in range(100):
count = count + 1
self.lock.release()
#方式二
lockA = threading.Lock()
lockB = threading.Lock()
rLock = threading.RLock()
condt = threading.Condition()
event = threading.Event()
def add(lockA):
global count
#定义当前资源只能单线程访问,锁住后完成资源调用一定要释放锁,不然会造成死锁状态,甚至程序崩溃
lockA.acquire()
for i in range(1000):
count = count + 1
#资源调用完毕,释放锁
lockA.release()
def addRunner():
for i in range(2):
th = threading.Thread(target=rloc, args=(rLock,))
#开启线程,从此刻起,多线程开始,主线程继续前行
th.start()
#调用Thread.join[timeout]将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间
th.join()
print '----- %s is start -----' % th.getName()
print "over"
#RLock允许在同一线程中被多次acquire,避免单线程出现思索情况
def rloc(rLock):
rLock.acquire()
for i in range(2):
rLock.acquire()
print i,
rLock.release()
rLock.release()
print "over!"
def rlocRun():
for i in range(2):
th = threading.Thread(target=rloc, args=(rLock,))
th.start()
print '----- %s is start -----' % th.getName()
print "over"
#现在出现复杂的场景,多个线程需要调用多个共同的资源,此时就需要threading.Condition出马,加入简单的说就是A搞完了A的事
# ,就发广播说明自己搞定了,其它人可以进来了,B同理。
def cond(cond):
#适合那种主动休眠,被动唤醒的场景
cond.acquire()
global count
for i in range(1000):
count = count + 1
#唤醒一个挂起的线程(如果存在挂起的线程),提醒当前的挂起的线程看看其它的锁开了没有,如果开了就搞其他的事。
#注意:notify()方法不会释放所占用的琐。
cond.notify()
#wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时
cond.wait(5)
#相信大家应该看出问题来了,最后一个线程咋办列,没人唤醒啊,这个时候应该做过一个判断
cond.release()
print "over!"
def condRun():
global condt
for i in range(0, 3):
th = threading.Thread(target=cond, args=(condt, ))
th.start()
print '----- %s is start -----' % th.getName()
print "over"
#此时可能会有一点问题,就是线程的同步(并发)问题怎么解决呢?此时threading.Event出马
def even(n, event):
while not event.isSet():
print 'Thread %s is ready' % n
time.sleep(1)
#同condition一样,挂起该线程,等待set开关
event.wait()
while event.isSet():
print 'Thread %s is running' % n
time.sleep(1)
def evenRun():
for i in range(0, 2):
th = threading.Thread(target=even, args=(i, event))
th.start()
time.sleep(3)
print '----- event is set -----'
event.set()
time.sleep(3)
print '----- event is clear -----'
event.clear()
if __name__ == "__main__":
Counter(lockA, "thread1").start()
addRunner()
rlocRun()
condRun()
evenRun()
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总》
希望本文所述内容对大家学习Python程序设计有所帮助。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









