1. 多线程的基本使用

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.')
# 对函数 run 创建5个线程
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 开始线程活动
t.start() time.sleep(0.01)
print('Main thread is finished.')
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Main thread is finished.
Thread is finished. # 上面打印的顺序是先打印 Main thread is finished.因为主线程已经完成了,而子线程里 slee(3),所以此时子线程尚未完成,大约3秒后,才打印的 Thread is finished.

PS. 线程类的使用

import threading
import time num = 0
lock = threading.Lock() # 互斥锁,因为多个线程要对共享的数据:num 进行修改,防止出现错误。 class MyThread(threading.Thread): # 继承线程类
def __init__(self):
super().__init__() # 写了__init__,就一定要继承父类的构造方法。父类的__init__的参数是默认参数,故可以不用重写父类的参数。 def task(self): # 自定义的函数
global num
if lock.acquire(): # 如果上锁成功,则执行:
num+=1
print(f'{self.name}, Num is : {num}') # 打印线程名和num的值
lock.release() # 释放锁,让数据供其他线程使用
time.sleep(1) def task2(self):
time.sleep(0.1)
print(f'{self.name}','Task2 is being called.')
time.sleep(1) def run(self): # 重写父类的run方法。每个单独的线程控制中,start()会自动调用 run()方法。
self.task()
self.task2() for i in range(10):
T = MyThread() # 针对每个线程对象,start()最多只能调用一次,否则会抛出错误。所以才每循环一次,在循环内部重新生成一个对象
T.start()

2. 等待子线程执行:join

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.') Tlist = []
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 开始线程活动
t.start()
Tlist.append(t) for t in Tlist: # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
# t.join(0.1) # 针对每个子线程,等待0.1秒,继续执行主线程
t.join() # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。 time.sleep(0.01)
print('Main thread is finished.')
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Thread is finished.
Main thread is finished. # 子线程使用了join方法,等待子线程执行完毕才继续执行主线程,所以打印顺序是正常的。

3. 守护线程

即只要主线程执行完毕,不管子线程状态如何,都会被强制杀掉。

import threading
import time def run(num):
print('Num: %s'% num)
time.sleep(3) if num == 4:
print('Thread is finished.') Tlist = []
for i in range(5):
# 创建线程,target:目标函数,args:函数的参数,使用元组的形式
t = threading.Thread(target=run,args=(i,))
# 设置为守护线程
t.setDaemon(True)
# 开始线程活动
t.start()
Tlist.append(t) for t in Tlist: # 针对每个子线程,等待子线程执行一段时间,再继续往下执行主线程。
t.join(0.1) # 对子线程等待0.1秒后,继续执行主线程
# t.join() # 没写时间,则默认等待子线程执行完毕,才继续往下执行主线程。 time.sleep(0.01)
print('Main thread is finished.')
print('Current Thread:',threading.activeCount()) # 打印当前活动线程数量,这是主线程最后一个语句,所以不管此时还有多少个活动的守护线程,当此句执行完毕,守护线程都会被杀掉。
结果:
Num: 0
Num: 1
Num: 2
Num: 3
Num: 4
Main thread is finished.
Current Thread: 6 # 少打印了 Thread is finished. 因为 主线程结束后,子线程就被杀掉了。

4. 线程锁

GIL锁:  Global Interpreter Lock,全局解释器锁。为了解决多线程之间数据完整性和状态同步的问题,在任意时刻只有一个线程在解释器中运行。这是CPython中的问题。

线程安全:在多线程中,共享的数据同一时间只能由一个线程执行。

互斥锁:(threading.Lock) 并不关心当前是哪个线程占有了该锁;如果该锁已经被占有了,那么任何其它尝试获取该锁的线程都会被阻塞,包括已经占有该锁的线程也会被阻塞。

递归锁:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源(已经占用该锁的线程,可以多次actuire,并不会阻塞)

死锁:死锁就是当一个线程已经占用了锁并且尚未释放,但是又有新的获取该锁的请求,亦或着两个线程分别占据着对方想要获取的锁,此时线程进入了阻塞的状态,就是死锁。

部份转自:https://www.jb51.net/article/74426.htm

部份转自:https://www.cnblogs.com/ArsenalfanInECNU/p/10022740.html

e.g.

互斥锁:threading.Lock

import threading

class MyThread(threading.Thread):
def run(self): # 这是重写的父类的run方法
global num
if mutex.acquire(): # 判断能否加锁,acquire()返回的是加锁的状态,加锁成功就是True
num = num+1
msg = self.name+' set num to '+str(num)
print(msg)
# mutex.acquire() # 这两句话如果不注释掉,就会进入死锁的状态。因为上一个锁还未释放,再次请求加锁,就会阻塞。
# mutex.release()
mutex.release() # 释放锁
num = 0
mutex = threading.Lock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()

普通方法:

import threading
import time def run(n):
global num
if mutex.acquire(): # 返回获取锁的结果,加锁成功为True,失败false
num = num+1
msg ='Thread-%s set num to ' %n + str(num)
print(msg)
mutex.release()
time.sleep(2) num = 0
mutex = threading.Lock() for i in range(5):
t = threading.Thread(target=run,args=(i+1,))
t.start()

递归锁:threading.RLock

import threading

class MyThread(threading.Thread):
def run(self):
global num
if mutex.acquire():
num = num+1
msg = self.name+' set num to '+str(num)
print(msg)
mutex.acquire() # 虽然再次acquire,但是并不会阻塞
mutex.release()
mutex.release()
num = 0
mutex = threading.RLock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()

5. 信号量 semaphore

信号量用于限制同时运行的线程数量

import threading
import time def run(n):
sema.acquire()
print('Thread: %s' %n)
time.sleep(2)
sema.release()
# 声明信号量,同时允许5个线程执行
sema = threading.BoundedSemaphore(5) for i in range(20):
t = threading.Thread(target=run,args=(i+1,))
t.start()

6. 事件:Event

事件可以用于多个线程进行简单通讯,事件可以控制一个内部 flag,初始时是 False,通过 set 方法使其变成 True,clear 方法使其变成 False,flag 为 False 时 wait 方法会一直阻塞直到flag 为True。

import threading
import time # 事件可以控制一个内部标志,通过set方法使其变成True,clear方法使其变成False,为False时wait方法会一直阻塞直到标志为True。
# 这个标志初始时是False event = threading.Event()
# event.set() # 设置flag为True
# event.clear() # 设置flag为False
# event.wait() # 一直等待(阻塞),直到有线程使用 set 方法将 flag 变成 True
# event.is_set() # 返回flag的值 def boss():
print('Boss: 今天加班5秒钟')
event.clear() # 清除 flag,使其值变为 false
time.sleep(5)
print("Boss: 时间到了,大家回家吧")
event.set() # 设置 flag,使其值变为 True def employee():
while True:
if event.is_set(): # 判断:如果 flag 为 True
print('Employee: 回家了!')
break
else:
print('Emplyee: 工作中,请勿打扰...')
event.wait() # 如果 flag 为 False,则使用 wait 方法一直等待,直到有线程将其设置为 True # 创建两个线程,分别为boss和employee,让它们根据 event 进行简单的通讯
b = threading.Thread(target=boss,)
e = threading.Thread(target=employee,)
b.start()
e.start()
结果:
Boss: 今天加班5秒钟
Emplyee: 工作中,请勿打扰...
Boss: 时间到了,大家回家吧
Employee: 回家了!

python 多线程、线程锁、事件的更多相关文章

  1. Python多线程-线程锁

    多线程修改一份数据时需要用到线程锁,以防止数据修改出错 #-*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threa ...

  2. 孤荷凌寒自学python第四十天python 的线程锁RLock

     孤荷凌寒自学python第四十天python的线程锁RLock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 因为研究同时在多线程中读写同一个文本文件引发冲突,所以使用Lock锁尝试同步, ...

  3. 孤荷凌寒自学python第三十九天python 的线程锁Lock

    孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...

  4. 第十五章、Python多线程同步锁,死锁和递归锁

    目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...

  5. Python学习---线程锁/信号量/条件变量同步/线程池1221

    线程锁 问题现象: 多线程情况下,CPU遇到阻塞会进行线程的切换,所以导致执行了tmp-=1的值还未赋值给num=tmp,另一个线程2又开始了tmp -=1,所以导致最后的值重复赋值给了num,所以出 ...

  6. python多线程中锁的概念

    1 2 3 4 5 6 7 8 mutex = threading.Lock() #锁的使用 #创建锁 mutex = threading.Lock() #锁定 mutex.acquire([time ...

  7. c++11多线程---线程锁(mutex)

    #include<mutex> 包含四类锁: 1      std::mutex    最基本也是最常用的互斥类 2      std::recursive_mutex  同一线程内可递归 ...

  8. python多线程--线程同步

    如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步. 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire ...

  9. 并发编程~~~多线程~~~线程queue, 事件event,

    一 线程queue 多线程抢占资源,只能让其串行. 互斥锁 队列 import queue q = queue.Queue() # 先进先出 q = queue.LifoQueue() # 先进后出 ...

  10. python的线程锁

    1.先看一个例子,一个进程可以起多个线程,多个线程都共享这个线程的内存 import threading import time num = 100 thread_lock = threading.L ...

随机推荐

  1. 阶段3 2.Spring_06.Spring的新注解_2 spring的新注解-Bean

    下面要解决第二部分的配置问题 这两行一出场,就表示可以通过调用构造函数实例化.因为这都是newInstance 上面的需要加上参数,下面的没有任何参数 下面这俩实现的效果不一样. 下面这个除了会创建对 ...

  2. Kotlin 的 @JvmStatic 和 @JvmField 注解

    这是关于 Java 静态方法和静态变量的一段代码: public class TestStatic { private int otherField = 0; public static final ...

  3. 求助,在gmssl中添加第三方库engine的问题

    求助gmssl的一个问题,想知道gmssl怎么添加自己的硬件engine,有搞过的大佬吗,求助.我现在将第三方的sdf标准库,在gmssl的源码中通过gmssl engine尝试添加总是报错libsd ...

  4. 应用安全 - Java - 插件 - IO - excel-streaming-reader - 漏洞汇总

    xlsx-streamer.jar的XXE漏洞 Date 类型XXE 影响范围 xlsx-streamer.jar-2.0.0及以下版本 复现

  5. 【神经网络与深度学习】卷积神经网络-进化史:从LeNet到AlexNet

    [卷积神经网络-进化史]从LeNet到AlexNet 本博客是[卷积神经网络-进化史]的第一部分<从LeNet到AlexNet> 如需转载,请附上本文链接:http://blog.csdn ...

  6. 【神经网络与深度学习】如何将别人训练好的model用到自己的数据上

    caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...

  7. 【VS开发】Cameralink接口

    目录 1 Camera Link接口的三种配置 ▪ Base Camera Link ▪ Medium Camera Link ▪ Full Camera Link 2 Camera Link三种接口 ...

  8. 浅谈python中字典append 到list 后值的改变问题

    看一个例子 ? 1 2 3 4 d={'test':1} d_test=d d_test['test']=2 print d 如果你在命令行实践的话,会发现你改动的是d_test ,但是d 也跟着改变 ...

  9. DataGridView中EnditCommit()调用之后,单元格的内容被全选了,每次输入都要鼠标点击定位到最后才能继续输入

    因为某些需求,DataGridView在输入一次内容,就要调用ECommitEdit(DataGridViewDataErrorContexts.Commit)来将内容提交,但是这样做之后,控件就会当 ...

  10. 启用hdfs的高可用

    cm-HDFS: 选择另外一个节点的做NN, 生产选node3 选择三个节点作journalNode, node2,3,4 填入journalNode的目录/dfs/jn 经过一系列步骤,如果没报错 ...