五、python高级:线程

一、多线程执行

1、使用前先导入  form  threading  import  Thread

2、t = Thread( target = test )  创建线程

3、t.start( ) 启动线程

4、主线程会等待所有的子线程结束后才结束

5、通过Thread子类完成创建多线程

 

二、线程共享全局变量

1、与进程不同,线程之间共享全局变量

   通过以上实例我们发现,经过两个子线程对全局变量 num 的修改,num 最终的值已经从 100 变成了 113,进一步证明了线程之间是共享全局变量的

 

2、由于线程之间共享全局变量,当子线程对全局变量进行操作时,可能会导致一些BUG的出现

如图,经过两个子线程的运行,最终全局变量 g_num 的值应为2000000,但是运行结果如下:

 

解决方法一: 主线程等待1秒后,再开启第二个线程

 

解决方法二:定义一个标志位,通过标志位状态来执行不同的线程

 

解决方法三:互斥锁

 ①当多个线程几乎同时修改某个共享数据时,需要进行同步控制,线程同步控制能够保证多个线程安全访问竞争资源,最简单的同步机制就是引入互斥锁,

②互斥锁为资源引入一个状态:锁定 / 非锁定

③某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他的线程不能更改,直到该线程释放资源,将资源状态改为“非锁定”,其他的线程才能再次锁定该资源,互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程操作下,数据的正确性

④互斥锁使用前先导入 

 

使用互斥锁时需要注意逻辑性,避免出现死锁

可重用锁:RLock(),出现多线程竞争资源时,如果无法熟练使用互斥锁,可以选择使用可重用锁,

以上实例,使用互斥锁会出现自锁现象,而使用可重用锁则没有问题。

 

 

三、线程之间的局部变量不共享

1、

如图,  threading.current_thread( ).name  可以获得线程名

 

2、

我们发现,虽然两个线程都去同一个函数中执行任务,但是局部变量g_num并不共享

 

四、Condition用法

  • acquire():线程锁,只有获取线程锁资格,该线程才能继续执行
  • release():释放锁,释放之后,其他线程才可以获取线程锁
  • wait():线程挂机,直到收到notify通知、或者超时(可选的,浮点数,单位是s)才会被唤醒,继续执行。wait()必须在获取线程锁的前提下才可以使用,否则会触发RuntimeError。
  • notify(n=1):唤醒其他挂机线程,默认唤醒一个正在等待该condition的线程,最多可唤醒n个挂机的线程。notify()必须在获取线程锁的前提下才可以使用,否则会触发RuntimeError。,notify()不会主动释放线程锁。
  • notifyAll():如果wait状态线程较多,使用该方法唤醒全部线程

 

五、Event用法

Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位为假,则线程等待直到信号被其他线程设置成真。这一点似乎和windows的event正好相反。 Event对象实现了简单的线程通信机制,它提供了设置信号,清除信号,等待等用于实现线程间的通信。

  • 设置信号:使用Event的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态,当使用event对象的set()方法后,isSet()方法返回真.
  • 清除信号:使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假
  • 等待:Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,则wait方法一直等待到其为真时才返回。
# make thread exit nicely
class MyThread9(threading.Thread):
	def __init__(self):
		threading.Thread.__init__(self)
	
	def run(self):
		global event
		while True:
			if event.isSet():
				logging.warning(self.getName() + " is Running")
				time.sleep(2)
			else:
				logging.warning(self.getName() + " stopped")
				break;
 
event = threading.Event()
event.set()
 
def Test9():
	t1=[]
	for i in range(6):
		t1.append(MyThread9())
	for i in t1:
		i.start()
	time.sleep(10)
	q =raw_input("Please input exit:")
	if q=="q":
		event.clear()
if __name__=='__main__':
	Test9()

 

六、守护线程与非守护线程

1、守护线程:线程一直运行而不阻塞主程序,即主程序不会等待该线程结束而结束,一旦所有的非守护线程结束,主程序就会结束。

2、非守护线程:主程序会在非守护线程结束之后再结束,即非守护线程会阻塞主程序。

3、默认情况下,线程都是非守护线程,使用setDaemon()方法,选择设置该线程是否为守护线程。

from threading import Thread
import time ,threading

def task(t):
    time.sleep(t)
    print(threading.currentThread().getName(),"end")

print("开始")
for i in range(5):
    t=Thread(target=task,args=(i,))
    t.setName("线程"+i)
    t.setDaemon(True)  # 设置线程为守护线程,即主程序不会等待该线程结束
    t.start()
    

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值