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. Eclipse如何安装Fat Jar

    〇.安装前准备 1.Fat Jar插件下载地址:https://sourceforge.net/projects/fjep/files/ 2.安装前请确认Eclipse版本:Help --> A ...

  2. python 引流

    Python给抖音自动点赞和评论,实现自动化运营! 都说抖音有毒,一刷就停不下来了.看来抖音这款产品紧紧抓住了人们内心深处的某些需求.当然今天不是来探讨抖音这款产品的啊.今天我们来学习如何用 Pyth ...

  3. Selenium 2自动化测试实战16(多窗口切换)

    一.多窗口切换 在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要主机切换到新打开的窗口上进行操作.WebDriver提供了switch_to.window()方法.可以实现在不同的窗口之间 ...

  4. 转载-Mysql主主复制架构配置

    Mysql主主复制架构配置 转载:原始出处 http://luoweiro.blog.51cto.com/2186161/658550MySQL主主复制结构区别于主从复制结构.在主主复制结构中,两台服 ...

  5. conftest.py作用范围

    前言 一个测试工程下是可以有多个conftest.py的文件,一般在工程根目录放一个conftest.py起到全局作用.在不同的测试子目录也可以放conftest.py,作用范围只在该层级以及以下目录 ...

  6. harbor无法上传镜像解决

    报错:[root@bogon harbor]# docker login 192.168.43.65:5000Username (admin): Password: Login Succeeded [ ...

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

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

  8. Redis 入门 3.2.2 命令

    Redis 入门 3.2 字符串类型 3.2.2 命令 1. 获得符合规则的键名列表 SET key value GET key   SET和GET是Redis中最简单的两个命令,他们实现的功能和编程 ...

  9. Shell编程、part3

    本节内容 1. shell流程控制 2. for语句 3. while语句 4. break和continue语句 5. case语句 6. shell编程高级实战 shell流程控制 流程控制是改变 ...

  10. netcore 实现一个简单的Grpc 服务端和客户端

    参考资料,和详细背景不做赘述. 首先定义prop 文件 syntax ="proto3"; package RouteGrpc; service HelloWorld{ rpc S ...