学习笔记----多任务-线程

3 篇文章 0 订阅
1 篇文章 0 订阅

多任务的概念
操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄咪咪地在后台同时运行着,只是桌面上没有显示而已。
并行:在计算机系统中能同时执行两个或多个处理的一种计算方法。[通俗说:一台四核计算机,每个单核cpu执行一个程序,并同时进行。简称:真的多任务]
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是同一个处理机上运行,但任一时刻点上只有一个程序在处理机上运行。[简称:假的多任务]

线程

python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装,可以更加方便的使用

1.使用threading模块

单线程执行

1 import time 
2 import threading
3 
4 def sing():
5         """唱歌 5秒钟"""
6         for i in range(5):
7                 print("正在唱:庸人自扰")
8                 time.sleep(1)
9 def main():
10        t1 = threading.Thread(target=sing)
11        t1.start()
 
12 if __name__ == "__main__":
13       main()

多线程执行

  1 import time 
  2 import threading
  3 
  4 def sing():
  5         """唱歌 5秒钟"""
  6         for i in range(5):
  7                 print("正在唱:庸人自扰")
  8                 time.sleep(1)
  9 
 10 def dance():                                                                             
 11         """跳舞 5秒钟"""
 12         for i in range(5):
 13                 print("----正在跳舞----")
 14                 time.sleep(1)
 15 
 16 def main():
 17         t1 = threading.Thread(target=sing)
 18         t2 = threading.Thread(target=dance)
 19         t1.start()
 20         t2.start()
 21 		while True:
 22				length = len(threading.enumerate())
 23				print("当前运行的线程数为:%d" % length)
 24				if length <= 1:
 25						break
 26
 27				time.sleep(0.5)
 28
 29 if __name__ == "__main__":
 30         main()

线程-注意

1.线程执行代码的封装

通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要继承 threading.Thread 就可以了,然后重写run方法

示例如下:

import threading
import time 

class MyThread(threading.Thread):
	def ran(self):
		for i in range(3):
			time.sleep(1)
			msg = "I'm"+self.name+"@"+str(i)
			print(msg)
if __name__ == "__main__":
	t = MyThread()
	t.start()

多线程-共享全局变量

  1 import threading                                                                         
  2 import time
  3 
  4 
  5 
  6 # 定义一个全局变量
  7 g_num = 100
  8 
  9 
 10 def test1():
 11         global g_num
 12         g_num += 1
 13         print("-----in test1 g_num=%d-----" % g_num)
 14 
 15 def test2():
 16         print("-----in test2 g_num=%d-----" % g_num)
 17 
 18 def main():
 19         t1 = threading.Thread(target=test1)
 20         t2 = threading.Thread(target=test2)
 21 
 22         t1.start()
 23         time.sleep(1)
 24 
 25         t2.start()
 26         time.sleep(1)
 27 
 28         print("------in main Thread g_num = %d" % g_num)
 29 
 30 if __name__ == "__main__":
 31         main()

运行结果:
-----in test1 g_num=101-----
-----in test2 g_num=101-----
------in main Thread g_num = 101

多线程开发可能遇到的问题

假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。

但是由于是多线程同时操作,有可能出现下面情况:

  1. 在g_num=0时,t1取得g_num=0。此时系统把t1调度为"sleeping"状态,把t2转换为“running”状态,t2也获得g_num=0
  2. 然后t2对得到的值进行加1并赋值给g_num,使得g_num=1
  3. 然后系统又把t2调度为“sleeping”,把t1转为“running”.线程t1又把它之前得到的0加1后赋值给g_num。
  4. 这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1

同步的概念

同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
“同”应理解为协同、协助、互相配合,而不是理解为一起动作。
如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B执行,再将结果给A;A再继续操作。

解决线程同时修改全局变量的方式
对于上述提出的计算错误的问题,可以通过线程同步来进行解决
思路,如下:

  1. 系统调用t1,然后获取到g_num的值为0,此时上一把锁,即不允许其他线程操作g_num
  2. t1对g_num的值进行+1
  3. t1解锁,此时g_num的值为1,其他线程就可以使用g_num了,而且是g_num的值不是0而是1
  4. 同理其他线程在对g_num进行修改时,都要先上锁,处理完后在解锁,在上锁的整个过程中不允许其他线程访问,就保证了数据的正确性

互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁为资源引入一个状态:锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

threading模块中定义了Lock类,可以方便的处理锁定:

# 创建锁
mutex = threading.Lock()

# 锁定
mutex.acquire()

# 释放
mutex.release()

注意:

  • 如果这个锁之前是没有上锁的,那么acquire不会堵塞
  • 如果再调用acquire对这个锁上锁之前,它已经被其他线程上了锁,那么此时acquire会堵塞,直到这个锁被解锁为止

死锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。

避免死锁

  • 程序设计时要尽量避免(银行家算法)
  • 添加超时时间

附录–银行家算法
简而言之:可以多个锁,但需明白什么时候该解开锁A,锁A会导致锁B解开,锁B导致锁C解开以此类推。

问题描述:

一个银行家拥有一定数量的资金,有若干个客户要贷款。每个客户必须在一开始就声明他所需贷款的总额。若该客户贷款总额不超过银行家的资金总数,银行家可以接受客户的要求。客户贷款是以每次一个资金单位(如1WRMB等)的方式进行的,客户在借满所需的全部单位款额之前可能会等待,但银行家须保证这种等待是有限的,可完成的。

例如:
有三个客户C1,C2,C3,向银行家借款,该银行家的资金总额为10个资金单位,其中C1客户要借9个资金单位,C2客户要借3个资金单位,C3客户要借8个资金单位,总计20个资金单位。某一时刻的状态,如图所示:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值