教程引言:
该系列教程会系统地讲解并发与并行的基础概念,以及如何使用Python进行并发编程。掌握并发编程,是成为一名优秀程序员所必须具备的基本功。
3.2.1 线程的通信
在2.3节讲解了进程间的通信,对于初学者来说,经常接触的是磁盘文件,所以最容易想到的进程通信方式是文件。同样地,线程间也可以通过文件来进行通信。线程A往文件中写入数据,线程B往文件中读出数据:
由于进程中的所有线程共享进程的地址空间,所以可以通过全局变量来进行通信。为理解这样的通信方式,我们看下面的一段Python代码:
# __desc__ = 线程通过全局变量进行通信 # 定义全局变量COUNTER,表示计数器 COUNTER = 0 # 定义线程处理函数threadA,表示线程A def threadA(): # 可以访问全局变量COUNTER if COUNTER > 10: # 执行相关的处理逻辑 pass # 定义线程处理函数threadB,表示线程B def threadB(): # 可以访问全局变量COUNTER if COUNTER < 0: # 执行相关的处理逻辑 pass在上文代码中定义了线程处理函数threadA与threadB,分别表示线程A与线程B,在线程处理函数中,通过全局变量COUNTER来进行通信,根据COUNTER的不同状态,来定义不同的处理逻辑。
在进程内部可以通过open方法来获取文件对象,然后保存在全局变量中。线程通信,实质是通过全局对象来进行通信。
3.2.2 线程的同步
进程同步是指多个进程在进行协同工作或数据共享的过程中可能会发生冲突,这时引入了一系列机制来对进程间的操作进行协调和制约。线程同步也是同样的道理,引入线程的同步机制,是为对线程间的并发操作进行协调和制约。进程内的多个线程对共享资源进行并发读写时,必须进行同步,否则会出现数据不一致的情况。
同学们考虑下面的这种简单情况:
进程内有一个全局变量,初始值1000,表示银行卡中的余额,进程中有两个线程不断进行消费,并更新全局变量的值。
(1) 线程A读取全局变量的值,获得初始值1000(2) 线程A消费200元用来缴纳水电费,并更新卡中的余额(3) 线程B读取全局变量,由于线程A尚未更新全局变量的值,所以同样获得初始值1000(4) 线程B消费100元用来缴纳电话费,并抢在线程A之前更新全局变量,此时全局变量的值为900(5) 线程B更新完银行卡的余额以后,线程A接着更新全局变量的值,由于线程一开始从全局变量读到的值为1000,所以执行的计算逻辑为1000-200,全局变量的值最终更新为800。(6) 实际中一共消费了300,卡中的余额应为1000-300 = 700,这样就出现了数据不一致的情况。
同进程同步一样,线程也可以通过互斥锁,信号量来进行同步,此外还可以通过条件变量来进行同步。在第六章介绍Python中的多线程编程时,会进行详细讲解。
3.2.3 知识要点
(1) 进程中的所有线程共享进程的地址空间,所以可以通过全局变量来进行通信(2) 线程同步与进程同步一样,引入同步机制是为对线程间的并发操作进行协调和制约。进程内的多个线程对共享资源进行并发读写时,必须进行同步,否则会出现数据不一致的情况。
3.2.4 课后习题
(1)根据2.3节与本节的内容,来理解何为线程安全(2)通过什么方法,可以编写进程安全和线程安全的代码?
关注微信公众号:Python在线课堂,学习Python视频课程以及其它的编程课程:tornado,django,web开发,网络爬虫,大数据分析,机器学习。公众号后台回复“学习资料”领取Python,web开发,网络爬虫,大数据分析,机器学习等学习资料。