最近学了下python中多线程的一些知识,在此总结一下。
几乎所有的操作系统都支持进程的概念,所有运行中的任务通常对应一个进程。当一个程序进入内存运行时,即变成一个进程。进程是处于运行过程中的程序,并且具有一定的独立功能。
进程是系统进行资源分配和调度的一个独立单位。包括三个特征:独立性,动态性,并发性。
多线程扩展了多进程的概念,使得同一个进程可以同时并发处理多个任务。
线程也被称为轻量级进程,线程是进程的执行单元。
线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程。
操作系统可以同时执行多个任务,每一个任务就是一个进程;进程可以同时执行多个任务,每一个任务就是一个线程。
多线程优点:
import threading
def action(max):
pass
#创建线程,
#target指定该线程要调度的目标方法
#args指定一个元组,以位置参数的形式为target指定的函数传入参数
#kwargs指定一个字典,以关键字参数的形式为target传入参数
#daemon指定所创建的线程是否为后台线程
t1 = threading.Thread(target=action, args=(100,))
#启动线程
t1.start()
#返回当前正在执行的线程对象
t = threading.current_thread()
#返回调用它的线程名字,同t.name
name = t.getName()
在线程的生命周期里,要经过新建、就绪、运行、阻塞和死亡5种状态。
当程序创建了一个Thread对象后,该线程处于新建状态。
start后处于就绪状态。
至于该线程何时开始运行,取决于python解释器中线程调度器的调度。
当发生如下情况时,线程将会进入阻塞状态:
join方法,让一个线程等待另一个线程完成的方法。当在某个程序执行流中调用其他线程的join方法时,调用线程将被阻塞,直到被join方法加入的join线程执行完成。
后台线程,任务是为了其他线程提供服务。例如python解释器的垃圾回收线程。
创建后台线程有两种方式:
线程睡眠:通过time模块的sleep(secs)函数来实现。使线程阻塞secs秒。
Thread的run方法不具有线程安全性——程序中有多个并发程序在修改同一个对象。
threading模块提供了Lock和RLock两个类,他们都提供了如下两个方法来加锁和释放锁:
Lock和RLock的区别:
代码模板:
class X:
#定义需要保证线程安全的方法
def m(self):
#加锁
self.lock.acquire()
try:
#需要保证线程安全的代码
#。。。方法体
#使用finally来保证释放锁
finally:
#修改完成,释放锁
self.lock.release()
通过使用Lock对象可以非常方便地实现线程安全的类,线程安全的类特征:
死锁:当两个线程互相等待对方释放同步监视器。
一旦出现死锁,整个程序既不会发生任何异常,也不会给出任何提示,所有线程都处于阻塞状态,无法继续。
避免死锁的出现:
当线程在系统中运行时,线程的调度具有一定的透明性,通常程序无法准确控制线程的轮换执行,如果有需要,可通过线程通信来保证线程的协调运行。
使用Event控制线程通信:
一个线程发出一个Event,另一个线程可通过该Event被触发。
Event本身管理一个内部旗标,程序可以通过Event的set()方法将该旗标设置为True,也可以调用clear方法设置为False。可以调用wait方法来阻塞当前线程,知道Event的旗标为True
模板:
class X:
def m1(self):
self.lock.acquire()
#如果为True
if self.event.is_set():
#...
#...
self.event.clear()
self.lock.release()
self.event.wait()
else:
self.lock.release()
self.event.wait()
def m2(self):
self.lock.acquire()
#如果为False
if not self.event.is_set():
#...
#...
self.event.set()
self.lock.release()
self.event.wait()
else:
self.lock.release()
self.event.wait()
系统启动一个新线程的成本是比较高的,因为涉及到与操作系统的交互。如果程序需要创建大量生存期很短暂的线程时,应该考虑使用线程池。
线程池在系统启动时即创建大量空闲线程,程序只需要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行。当函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成K线状态,等待下一个函数。
线程池的基类是concurrent.futures模块中的Executor,Executor提供两个子类,ThreadPoolExecutor和ProcessPoolExecutor
Executor常用方法:
Future常用方法:
例子:
from concurrent.futures import ThreadPoolExecutor
import threading
import time
def action(max):
pass
pool = ThreadPoolExecutor(max_workers=2)
future = pool.submit(action,50)
print(future.done())
print(future.result())
pool.shutdown()