Python多线程编程1----Python对多线程的支持

多线程编程必须理解的一些基本概念,适用于所有编程语言。内容:

并发式编程

不同的编程范式对软件有不同的视角,并发式编程将软件看作任务和资源的组合-----任务之间竞争和共享资源,当资源满足是执行任务,否则等待资源。

并发式编程使得软件易于理解和重用,在某些场景能够极大提高性能。

多任务操作系统

要实现并发,首先要操作系统的支持。现在的操作系统大部分都是多任务操作系统,可以”同时“执行多个任务。

多任务可以在进程或线程的层面执行。

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间。多任务操作系统可以”并发“执行这些进程。

线程是指进程中乱序、多次执行的代码块,多个线程可以“同时”运行,所以认为多个线程是“并发”的。多线程的目的是为了最大限度的利用CPU资源,比如一个JVM进程中,所有的程序代码都以线程的方式运行。

这里面的“同时”、“并发”只是一种宏观上的感受,实际上从微观层面看只是进程/线程的轮换执行,只不过切换的时间非常短,所以产生了“并行”的感觉。

多线程VS多进程

操作系统会为每个进程分配不同的内存块,而多个线程共享进程的内存块。这带来最直接的不同就是创建线程的开销远小于创建进程的开销。

同时,由于内存块的不同,所有进程之间的通信相对困难,需要采用pipe/named  pipe ,signal ,message queue ,shared  memory ,socket 等手段;而线程间的通信简单快速,就是共享进程内的全部变量。

但是,进程的调度由操作系统负责,线程的调度就需要我们自己来考虑,避免死锁,饥饿,活锁,资源枯竭等情况发生,这回增加一定的复杂度。而且,由于线程之间共享内存,我们还需要考虑线程安全性的问题。

线程安全

 因为线程间共享进程中的全局变量,所以当其他线程改变了共享的变量时,可能会对本线程产生影响。所谓线程安全的约束就是指一个函数被多个并发线程反复调用时,要一直产生正确的结果。要保证线程安全,主要是通过加锁的方式保证共享变量的正确访问。

比线程安全更严格的约束是“可重入性”,即函数在一个线程内执行的过程中被暂停,接下来又在另一个线程内被调用,之后在返回原线程继续执行。在整个过程中都能保证正确执行。保证可重入性,通常通过制作全局变量的本地拷贝来实现。

线程的生命周期

所谓的线程生命周期,其实就是某对象的包含产生和销毁的一张状态图。如上图所示:

各状态的说明如下:

New新建                新创建的线程经过初始化后,进入Runnable状态。

Runnable就绪       等待线程调度。调度后进入运行状态。

Running运行

Blocked阻塞          暂停运行,解除阻塞后进入Runnable状态重新等待调度。

Dead消亡               线程方法执行完毕返回或者异常终止


可能有3种情况从Running进入Blocked:

同步:线程中获取同步锁,但是资源已经被其他线程锁定是,进入Locked状态,知道该资源可获取(获取的顺序有Lock队列控制)

睡眠:线程运行sleep()或join()方法后,线程进入Sleeping 状态。区别在于sleep等待固定的时间,而join是等待子线程执行完。当然join也可以指定一个“超时时间”。从语义上来说,如果两个线程a,b,在a中调用b.join(),相当于合并(join)成一个线程。最常见的情况是在主线程中join所有的子线程。

等待:线程中执行wait()方法后,线程进入Waiting状态,等待其他线程的通知(notify)。

线程的类型

主线程:当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(main thread )。每个进程至少都有一个主线程,主线程通常最后关闭。

子线程:在程序中创建的其他线程,相对于主线程来说就是这个主线程的子线程。

守护线程:daemon thread,对线程的一种标识。守护线程为其他线程提提供服务,如JVM的垃圾回收线程。当剩下的全是守护线程时,进程退出。

前台线程:相对于守护线程的其他线程称为前台线程。

Python对多线程的支持

虚拟机层面

Python虚拟机使用GIL(Global Interpreter Lock,全局解释器锁)来互斥线程对共享资源的访问,暂时无法利用多处理器的优势。

语言层面

在语言层面,Python对多线程提供了很好的支持,Python中多线程相关的模块包括:thread,threading,Queue。可以方便地支持创建线程、互斥锁、信号量、同步等特性。

thread:多线程的底层支持模块,一般不建议使用。

threading:对thread进行了封装,将一些线程的操作对象化,提供了下列类:


Thread 线程类
Timer与Thread类似,但要等待一段时间后才开始运行
Lock锁原语
RLock可重入锁。使单线程可以再次获得已经获得的锁
Condition条件变量,能让一个线程停下来,等待其他线程满足某个条件。
Event通用的条件变量。多个线程可以等待某个事件发生,在事件发生后,所有的线程都被激活。
Semaphore为等待锁的线程提供一个类似“等候室”的结构
BoundedSemaphore与Semaphore类似,但不允许超过初始值

Queue:实现了多生产者(Producer)、多消费者(Consumer)的队列,支持锁原语,能够在多个线程之间提供很好的同步支持

Queue队列
LifoQueue后入先出(LIFO)队列
PriorityQueue优先队列

其中Thread类是主要的线程类,可以创建进程实例。该类提供的函数包括:

getName(self )返回线程的名字
isAlive(self )布尔标志,表示这个线程是否还在运行中
isDaemon(self)返回线程的daemon标志
join(self,timeout=None )程序挂起,直到线程结束
run(self)定义线程的功能函数
setDaemon(self,daemonic) 把线程的daemon标志设为daemonic
setName(self,name)设置线程的名字
start(self)开始线程执行

第三方支持

如果你特别在意性能,还可以考虑一些“微线程”的实现。

Stackless Python :Python的一个增强版本,提供了对微线程的支持。微线程是轻量级的线程,在多个线程间切换锁需要的时间更少,占用的资源也更少。

greenlet:是Stackless的副产品,其将微线程称为“tasklet”。tasklet运行在伪并发中,使用channel进行同步数据交换。而“greenlet”是更加原始的微线程的概念,没有调度。你可以自己构造微线程的调度器,也可以使用greenlet实现高级的控制流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值