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. 从txt导入数据到mysql

    当要往mysql的table中录入数据量大的时候,直接从txt录入已有数据是一个愉快的选择. 在录入数据前要做一些格式上的准备 1. txt编码要是utf-8,无BOM 2. 每行以\t\n结尾,每列 ...

  2. 基于 Node.js 的服务器自动化部署搭建实录

    基于 Node.js 的服务器自动化部署搭建实录 在服务器上安装 Node.js 编写拉取仓库.重启服务器脚本 配置 Github 仓库的 Webhook 设置 配置 Node.js 脚本 其他问题 ...

  3. 安装 Genymotion及其破解版 测试能用的方法

    第一,照下面的教程  先安装 https://blog.csdn.net/sxk874890728/article/details/82721746 安装 Genymotion及其破解版 2018年0 ...

  4. java游戏服务器--简单工厂模式

    先来学习下简单工厂模式! 我们知道在游戏里有很多的场景,例如:帮派场景,副本场景,野外场景... 现在我们有这样的需求: 1.我们需要进入帮派场景时---开始执行帮派任务. 2.我们需要进入副本场景时 ...

  5. Linux字符界面字符颜色显示

    一.字符颜色 #!/bin/bash #字符颜色显示 #-e:允许echo使用转义 #\033[:开始位 #\033[0m:结束位 #\033等同于\e echo -e "\033[30m黑 ...

  6. CVPR2019 论文解读| BASNet:关注边界的显著性目标检测

    作者 | 文永亮 学校 | 哈尔滨工业大学(深圳) 研究方向 | 目标检测 概要 ​ 这是一篇发表于CVPR2019的关于显著性目标检测的paper,<BASNet:Boundary-Aware ...

  7. Python 爬取煎蛋网妹子图片

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2017-08-24 10:17:28 # @Author : EnderZhou (z ...

  8. Matcher和Pattern总结

    Matcher.Pattern简介 java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包.它包括两个类:Pattern和Matcher Pattern 一个Pat ...

  9. [ZJOI2007]时态同步 题解

    题面 这道题是一道比较水的XXOI题: 我们可以发现,反着思考题目就变为了让所有叶子节点同时发出信号,然后这些信号同时到达根节点: 可以证明,这样答案不会改变: 那么我们可以自下而上dfs(),设f[ ...

  10. 问题:C++类的静态成员变量如何初始化

    C++类的静态成员变量属于该类,在该类所有的对象间共享. 要弄清如何初始化,首先要明白声明.定义.初始化三个概念的不同. 声明:指定变量的名字和类型,可以多次声明. 定义:为该成员变量分配存储空间,有 ...