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. React之js实现跳转路由

    1.新增知识 /* 实现js跳转路由:https://reacttraining.com/react-router/web/example/auth-workflow 1.要引入Redirect im ...

  2. Selenium 2自动化测试实战13(设置元素等待)

    一.设置元素等待 若在加载某个元素时延迟而造成的ElementNotVisbleException的情况出现,那么就会降低自动化脚本的稳定性,可以通过设置元素等待改善这种问题造成的不稳定. webdr ...

  3. Counter() most_common()

    1 不仅可以统计list中元素的出现次数,也可以对str中的元素进行统计 # collections包中的Counter用于统计str list 中元素出现次数 from collections im ...

  4. 慕课网_文件传输基础——Java IO流

    第1章 文件的编码 1-1 文件的编码 (15:07) 第2章 File 类的使用 2-1 File 类常用 API 介绍 (10:50) import java.io.File; import ja ...

  5. 嵌套的JsonObject与JSONArray的取值---JSON中嵌套JSONArray

    在复杂的JSON数据的格式中,往往会对JSON数据进行嵌套,这样取值会比之前的取值稍微复杂一点,但是只要思路清晰,其实取法还是一样的.就跟if else语句一样,如果if中套if,if中再套if,写的 ...

  6. 【HANA系列】SAP HANA跟我学HANA系列之创建计算视图一

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA跟我学HANA系 ...

  7. C#学习笔记二 (资源托管,泛型,数组和元组,运算符和类型强制转换)

     托管和非托管资源 1.托管资源是指GC管理的内存空间,非托管资源是指文件句柄,网络连接,数据库连接等. 2.方法中临时申请的变量,被存放在栈中.栈存储非对象成员的值数据.例如在方法中有B b=new ...

  8. LeetCode.965-单一二叉树(Univalued Binary Tree)

    这是悦乐书的第366次更新,第394篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第228题(顺位题号是965).如果树中的每个节点具有相同的值,则二叉树是单一的.当且仅 ...

  9. 【神经网络与深度学习】Caffe部署中的几个train-test-solver-prototxt-deploy等说明

    1:神经网络中,我们通过最小化神经网络来训练网络,所以在训练时最后一层是损失函数层(LOSS), 在测试时我们通过准确率来评价该网络的优劣,因此最后一层是准确率层(ACCURACY). 但是当我们真正 ...

  10. XCode8.3真机调试设置

    本文使用XCode8.3.3 首先XCode->Preferncs,进入下面的界面 点击左下角“+”号,并输入账号,然后点击Manage Certificates,左下角添加IOS develo ...