详解python多线程、锁、event事件机制的简单使用


Posted in Python onApril 27, 2018

线程和进程

1、线程共享创建它的进程的地址空间,进程有自己的地址空间

2、线程可以访问进程所有的数据,线程可以相互访问

3、线程之间的数据是独立的

4、子进程复制线程的数据

5、子进程启动后是独立的 ,父进程只能杀掉子进程,而不能进行数据交换

6、修改线程中的数据,都是会影响其他的线程,而对于进程的更改,不会影响子进程

threading.Thread

Thread 是threading模块中最重要的类之一,可以使用它来创建线程。有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法;另一种是创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入。
先来看看通过继承threading.Thread类来创建线程的例子:

import threading
import time

class MyThread(threading.Thread):
 def __init__(self, arg):
  # super(MyThread, self).__init__() # 新式类继承原有方法写法
  threading.Thread.__init__(self)
  self.arg = arg

 def run(self):
  time.sleep(2)
  print(self.arg)

for i in range(10):
 thread = MyThread(i)
 print(thread.name)
 thread.start()

另外一种创建线程的方法:

import threading
import time

def process(arg):
 time.sleep(2)
 print(arg)

for i in range(10):
 t = threading.Thread(target=process, args=(i,))
 print(t.name)
 t.start()

Thread类还定义了以下常用方法与属性:

Thread.getName() 获取线程名称

Thread.setName() 设置线程名称

Thread.name 线程名称

Thread.ident 获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法之后该属性才有效,否则它只返回None

判断线程是否是激活的(alive)。从调用start()方法启动线程,到run()方法执行完毕或遇到未处理异常而中断 这段时间内,线程是激活的

Thread.is_alive()
Thread.isAlive()

Thread.join([timeout]) 调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束

Python GIL(Global Interpreter Lock)

GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL。

线程锁的使用:

# 锁:GIL 全局解释器 它是为了保证线程在运行过程中不被抢占
number = 0
lock = threading.RLock() # 创建锁


def run(num):
 lock.acquire() # 加锁
 global number
 number += 1
 print(number)
 time.sleep(2)
 lock.release() # 释放锁

for i in range(10):
 t = threading.Thread(target=run, args=(i, ))
 t.start()

Join & Daemon

主线程A中,创建了子线程B,并且在主线程A中调用了B.setDaemon(),这个的意思是,把主线程A设置为守护线程,这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出.这就是setDaemon方法的含义,这基本和join是相反的。此外,还有个要特别注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起。

class MyThread1(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)

 def run(self):
  print("thread start")
  time.sleep(3)
  print('thread end')

print('main start')
thread1 = MyThread1()
# thread1.setDaemon(True)  # 设置子线程是否跟随主线程一起结束
thread1.start()
time.sleep(1)
print('satrt join')
# thread1.join() # 使主线程阻塞,直至子线程运行完毕再继续主线程
print('end join')
def run(n):
 print('[%s]------running----\n' % n)
 time.sleep(2)
 print('--done--')


def main():
 for i in range(5):
  t = threading.Thread(target=run, args=[i,])
  t.start()
  # t.join()
  print('starting thread', t.getName())


m = threading.Thread(target=main,args=[])
# m.setDaemon(True) # 将主线程设置为Daemon线程,它退出时,其它子线程会同时退出,不管是否执行完任务
m.start()
# m.join() # 使主线程阻塞,直至子线程运行完毕再继续主线程
print("---main thread done----")

线程锁(互斥锁Mutex)

一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况?

num = 100 # 设定一个共享变量
def subNum():
 global num # 在每个线程中都获取这个全局变量
 print('--get num:', num)
 time.sleep(2)
 num -= 1 # 对此公共变量进行-1操作
thread_list = []
for i in range(100):
 t = threading.Thread(target=subNum)
 t.start()
 thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕
 t.join()
print('final num:', num)
# 加锁版本
def subNum():
 global num # 在每个线程中都获取这个全局变量
 print('--get num:', num)
 time.sleep(1)
 lock.acquire() # 修改数据前加锁
 num -= 1 # 对此公共变量进行-1操作
 lock.release() # 修改后释放

num = 100 # 设定一个共享变量
thread_list = []
lock = threading.Lock() # 生成全局锁
for i in range(100):
 t = threading.Thread(target=subNum)
 t.start()
 thread_list.append(t)
for t in thread_list: # 等待所有线程执行完毕
 t.join()
print('final num:', num)

Rlock与Lock的区别:

RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。否则会出现死循环,程序不知道解哪一把锁。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的锁

Events

Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位真,则其他线程等待直到信号接触。
Event对象实现了简单的线程通信机制,它提供了设置信号,清除信号,等待等用于实现线程间的通信。

event = threading.Event() 创建一个event

1 设置信号
event.set()

使用Event的set()方法可以设置Event对象内部的信号标志为真。Event对象提供了isSet()方法来判断其内部信号标志的状态。
当使用event对象的set()方法后,isSet()方法返回真

2 清除信号
event.clear()

使用Event对象的clear()方法可以清除Event对象内部的信号标志,即将其设为假,当使用Event的clear方法后,isSet()方法返回假

3 等待
event.wait()

Event对象wait的方法只有在内部信号为真的时候才会很快的执行并完成返回。当Event对象的内部信号标志位假时,
则wait方法一直等待到其为真时才返回。也就是说必须set新号标志位真

def do(event):
 print('start')
 event.wait()
 print('execute')

event_obj = threading.Event()
for i in range(10):
 t = threading.Thread(target=do, args=(event_obj,))
 t.start()

event_obj.clear()
inp = input('输入内容:')
if inp == 'true':
 event_obj.set()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python可变参数用法实例分析
Apr 02 Python
Python实现调度算法代码详解
Dec 01 Python
python+mysql实现学生信息查询系统
Feb 21 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
May 15 Python
python3 selenium自动化测试 强大的CSS定位方法
Aug 23 Python
在django中使用apscheduler 执行计划任务的实现方法
Feb 11 Python
tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this T
Jun 22 Python
python 如何读、写、解析CSV文件
Mar 03 Python
Python爬虫之爬取最新更新的小说网站
May 06 Python
python plt.plot bar 如何设置绘图尺寸大小
Jun 01 Python
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
Apr 11 Python
python实现手机推送 代码也就10行左右
Apr 12 Python
Python Requests模拟登录实现图书馆座位自动预约
Apr 27 #Python
Python多线程中阻塞(join)与锁(Lock)使用误区解析
Apr 27 #Python
python队列queue模块详解
Apr 27 #Python
浅谈tensorflow1.0 池化层(pooling)和全连接层(dense)
Apr 27 #Python
python线程中同步锁详解
Apr 27 #Python
python数字图像处理之高级形态学处理
Apr 27 #Python
python线程池threadpool实现篇
Apr 27 #Python
You might like
推荐文章系统(一)
2006/10/09 PHP
Apache服务器无法使用的解决方法
2013/05/08 PHP
CodeIgniter生成网站sitemap地图的方法
2013/11/13 PHP
laravel中短信发送验证码的实现方法
2018/04/25 PHP
PHP单文件上传原理及上传函数的封装操作示例
2019/09/02 PHP
使用CDN和AJAX加速WordPress中jQuery的加载
2015/12/05 Javascript
js针对ip地址、子网掩码、网关的逻辑性判断
2016/01/06 Javascript
java中String类型变量的赋值问题介绍
2016/03/23 Javascript
JavaScript之class继承_动力节点Java学院整理
2017/07/03 Javascript
Node.js创建Web、TCP服务器
2017/12/05 Javascript
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
JavaScript实现星级评价效果
2019/05/17 Javascript
jQuery中使用validate插件校验表单功能
2019/05/24 jQuery
vue项目中运用webpack动态配置打包多种环境域名的方法
2019/06/24 Javascript
微信小程序网络请求实现过程解析
2019/11/06 Javascript
解决Ant Design Modal内嵌Form表单initialValue值不动态更新问题
2020/10/29 Javascript
Python 流程控制实例代码
2009/09/25 Python
python操作gmail实例
2015/01/14 Python
详解Python中的条件判断语句
2015/05/14 Python
python如何读写csv数据
2018/03/21 Python
Python 查找字符在字符串中的位置实例
2018/05/02 Python
Python tkinter的grid布局及Text动态显示方法
2018/10/11 Python
通过shell+python实现企业微信预警
2019/03/07 Python
python3实现弹弹球小游戏
2019/11/25 Python
Python交互环境下打印和输入函数的实例内容
2020/02/16 Python
django 读取图片到页面实例
2020/03/27 Python
Html5 webRTC简单实现视频调用的示例代码
2020/09/23 HTML / CSS
香港彩色隐形眼镜在线商店:Stunninglens(全球免费送货)
2019/05/10 全球购物
中层干部竞争上岗演讲稿
2014/01/13 职场文书
法学求职信
2014/06/22 职场文书
2014优秀党员事迹材料
2014/08/14 职场文书
最新离婚协议书范本
2014/08/19 职场文书
商务英语求职信范文
2015/03/19 职场文书
企业安全生产检查制度
2015/08/06 职场文书
导游词之韩国济州岛
2019/10/28 职场文书
Redis如何一键部署脚本
2021/04/12 Redis