day36 joinablequeue、多线程理论、多线程的两种使用方式、守护线程、互斥锁、死锁、递归锁、信号量
1、joinablequeue队列
joinablequeue与queue一样,也是一种队列,其继承自queue,也有queue中的put 与get 方法,但是在joinablequeue中有自己的 task_done 与 join方法
task_done方法:
记录从队列中取出的数据是否执行完毕
join方法:
会等待对列取完后才会执行后续的代码,相当于是一个阻塞操作,与进程的join方法相似
2、joinablequeue方法及守护进程的应用
import time
import random
from multiprocessing import Process,JoinableQueue
def consumer(name,q):
while True:
res=q.get()
if res is None:break
time.sleep(random.randint(1,3))
print('%s 吃了 %s' %(name,res))
q.task_done()
def producer(name,q,food):
for i in range(5):
time.sleep(random.randint(1,2))
res='%s%s' %(food,i)
q.put(res)
print('%s 生产了 %s' %(name,res))
if __name__ == '__main__':
q=JoinableQueue()
#2、生产者们
p1=Process(target=producer,args=('lee',q,'包子'))
p2=Process(target=producer,args=('andy',q,'水果'))
#3、消费者们
c1=Process(target=consumer,args=('aaa',q))
c1.daemon=True
p1.start()
p2.start()
c1.start()
# 确定生产者确确实实已经生产完毕
p1.join()
p2.join()
p3.join()
# 在生产者生产完毕后,开始等待队列中所有的数据被取完,且执行完毕(调用了task_done方法)
q.join()
print('主进程结束')
3、多线程理论
什么是多线程?
多线程就是多个正在执行的线程
线程就相当于流水线,线程时程序运行的最小单位,是一步一步进行的流程
为什么需要多线程:
在以前的学习中,我们认识了多进程,那为什么还需要多线程呢?
实际上这是一个误区,多进程与多线程是完全不同的两种事物,进程时资源分配的最小单位,而线程时程序执行的最小单位,一个进程中可以有多个线程,在我们创建进程时,实际上已经创建了一条主线程,进程只是资源的存放地 一以及线程的执行地,进程相当于实一个车间,线程相当于实进程中的一条流水线
多线程与多进程相比的优缺点:
进程是一个资源单位,创建进程开辟内存空间,将数据进行导入或者复制,在开启一个主线程,在进行执行
线程是一个执行单位,创建线程的时候既不需要开辟空间,也不需要进行代码或者数据的赋值,只是单纯的创建一个线程,使用进程的各种资源以及数据
在线程中数据是共享的,但是在进程中数据时不能互相访问的
from threading import Thread
a = 10
def task():
global a
print("子 running...")
a = 20
t1 = Thread(target=task)
t1.start()
t1.join() # 主线程等待子线执行完毕
print(a)
#
线程的创建
在python中,线程的创建于进程的创建基本相同
import multiprocessing.process
t = threading.Thread(target=test)
t.strat()
3、多线程创建的两种方式:
与多进程相同,一种方式是直接将要执行的函数作为参数传入到Thread中,另一种是创建自己的类,继承自Thread 类,再重写Thread类中的run方法
4、守护线程
与进程中的守护进程相似,在线程中,可以使用的deamon方法将一个子线程设置为守护线程,当主线程执行完毕后直接将守护线程一起带走
from threading import Thread
import time
def task():
print("子1running......")
time.sleep(100)
print("子1over......")
def task2():
print("子2running......")
time.sleep(4)
print("子2over......")
t = Thread(target=task)
t.daemon = True
t.start()
t2 =Thread(target=task2)
t2.start()
print("主over")
# 子 1 run 子2 run 主 子over 子2over 结束了
主线程代码执行 完毕后 不会立即结束 会等待其他子线程结束
主 会等待非守护线程 即t2
主线程会等待所有非守护线程结束后结束
守护线程会等到所有非守护线程结束后结束 ! 前提是除了主线程之外 还有后别的非守护
当然如果守护线程已经完成任务 立马就结束了
皇帝如果活着 守护者 妃子死了 皇帝正常运行 皇帝死了 无论守护者是否完成任务 都立即结束
5、互斥锁
在线程中,由于资源是共享的,所以多线程如果对主线程的数据进行修改,那么如果不加锁就会产生 数据的错乱,造成安全问题,所以此时需要进行加锁,在线程中,锁的创建与使用跟多进程完全像似,但是也有些许不同
from threading import Thread,enumerate,Lock
import time
number = 10
lock = Lock()
def task():
global number
lock.acquire()
a = number
time.sleep(0.1)
number = a - 1
lock.release()
for i in range(10):
t = Thread(target=task)
t.start()
for t in enumerate()[1:]:
# print(t)
t.join()
print(number)
# 用于访问当前正在运行的所有线程
# print(enumerate())
线程与进程中的锁的创建有些许不同,在进行进程中锁的创建时,需要将锁加入到if __name__ == “__main__”
中,而在线程中,创建的锁在主线程中创建就可以了,这是因为创建进程时会导入主进程的数据,会产生多把锁,但是创建线程就只是创建了一个流水线,数据等都是使用主线程的,所以只需要在主线程中创建一把锁进行了
6、死锁
死锁问题指的是当程序中使用了两把锁时,而数据只有在拿到两把锁时才可以使用,那么如果一个线程拿到了一把锁,另一个线程拿到了另一把锁,他们都等着对方的锁realease,这样就会产生死锁问题
import time
# 盘子
lock1 = Lock()
# 筷子
lock2 = Lock()
def eat1():
lock1.acquire()
print("%s抢到了盘子" % current_thread().name)
time.sleep(0.5)
lock2.acquire()
print("%s抢到了筷子" % current_thread().name)
print("%s开吃了!" % current_thread().name)
lock2.release()
print("%s放下筷子" % current_thread().name)
lock1.release()
print("%s放下盘子" % current_thread().name)
def eat2():
lock2.acquire()
print("%s抢到了筷子" % current_thread().name)
lock1.acquire()
print("%s抢到了盘子" % current_thread().name)
print("%s开吃了!" % current_thread().name)
lock1.release()
print("%s放下盘子" % current_thread().name)
lock2.release()
print("%s放下筷子" % current_thread().name)
t1 = Thread(target=eat1)
t2 = Thread(target=eat2)
t1.start()
t2.start()
7、递归锁
产生死锁的原因有两种,一种是上面描述的多把锁被多个线程持有,这样就会产生死锁问题,另一个问题就是如果只有一把锁,但是一个人使用这把锁acquire了两次就会产生死锁问题
对于这种死锁问题,我们可以通过检查代码来进行避免,但是这个是锁的问题,在python中,设置了另一种锁,叫做递归锁,不会因为一个线程把一把锁进行两次acquire就会死锁
这种锁就是递归锁 ——> Rlock
from threading import RLock, Lock, Thread
# l = Lock()
#
# l.acquire()
# print("1")
# l.acquire()
# print("2")
l = RLock()
# l.acquire()
# print("1")
# l.acquire()
# print("2")
def task():
l.acquire()
print("子run......")
l.release()
# 主线程锁了一次
l.acquire()
l.acquire()
l.release()
l.release()
t1 = Thread(target=task)
t1.start()
在使用Rlock时与使用Lock完全相同,但是在遇到了上方的第二种死锁问题时就不会阻塞,但是,需要注意的是,执行了几次acquire就需要执行几次release
7、信号量
信号量的意思就是被锁定的代码可以被多个线程访问
其与Lock方法的不同是,Lock只能由一个线程进行访问
信号量:Semaphore
from threading import Semaphore, Thread
import time
s = Semaphore(5)
def task():
s.acquire()
print("子run")
time.sleep(3)
print("子over")
s.release()
for i in range(10):
t = Thread(target=task)
t.start()
day36 joinablequeue、多线程理论、多线程的两种使用方式、守护线程、互斥锁、死锁、递归锁、信号量的更多相关文章
- day 33 什么是线程? 两种创建方式. 守护线程. 锁. 死锁现象. 递归锁. GIL锁
一.线程 1.进程:资源的分配单位 线程:cpu执行单位(实体) 2.线程的创建和销毁开销特别小 3.线程之间资源共享,共享的是同一个进程中的资源 4.线程之间不是隔离的 5.线程可不需 ...
- python 线程(创建2种方式,锁,死锁,递归锁,GIL锁,守护进程)
###############总结############ 线程创建的2种方式(重点) 进程:资源分配单位 线程:cpu执行单位(实体) 线程的创建和销毁的开销特别小 线程之间资源共享,是同一个 ...
- python并发编程-多线程实现服务端并发-GIL全局解释器锁-验证python多线程是否有用-死锁-递归锁-信号量-Event事件-线程结合队列-03
目录 结合多线程实现服务端并发(不用socketserver模块) 服务端代码 客户端代码 CIL全局解释器锁****** 可能被问到的两个判断 与普通互斥锁的区别 验证python的多线程是否有用需 ...
- Java多线程13:读写锁和两种同步方式的对比
读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...
- 【Python】python 多线程两种实现方式
目前python 提供了几种多线程实现方式 thread,threading,multithreading ,其中thread模块比较底层,而threading模块是对thread做了一些包装,可以更 ...
- python 多线程两种实现方式,Python多线程下的_strptime问题,
python 多线程两种实现方式 原创 Linux操作系统 作者:杨奇龙 时间:2014-06-08 20:24:26 44021 0 目前python 提供了几种多线程实现方式 thread,t ...
- Redis两种持久化方式(RDB&AOF)
爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis所需内存 超过可用内存怎么办 Redis修改数据多线程并发—Red ...
- java的两种同步方式, Synchronized与ReentrantLock的区别
java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock. 相似点: 这两种同步方式有很多相似之处,它们都是加锁 ...
- 软件公司的两种管理方式 总体来说,这个世界上存在两种不同的软件公司的组织结构。我把他们叫做 Widget Factory(小商品工厂) 和 Film Crews(电影工作组
软件公司的两种管理方式 一个简单的回答应该是——“因为在我们的社会里,我们总是会认为薪水和会和职位的层次绑在一起”.但是,这个答案同时也折射出一个事实——我们的薪资是基于我们的所理解的价值,但这并没有 ...
随机推荐
- spring boot 入门 使用spring.profiles.active来分区配置(转)
很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用profile在不同的环境 ...
- Leetcode部分题目整理(Javascript)
3.无重复字符的最长子串 /** * @param {string} s * @return {number} */ var lengthOfLongestSubstring = function(s ...
- vim 插件安装
一.pathogen简介 通常情况下安装vim插件,通常是将所有的插件和相关的doc文件都安装在中一文件夹中,如将插件全部安装在/usr/share/vim/vim73/plugin/目录下,将帮助文 ...
- 并发编程入门(三): 使用C++11实现无锁stack(lock-free stack)
前几篇文章,我们讨论了如何使用mutex保护数据及使用使用condition variable在多线程中进行同步.然而,使用mutex将会导致一下问题: 等待互斥锁会消耗宝贵的时间 - 有时候是很多时 ...
- ege图形库之简单贪吃蛇(c++)
第二次做动画显示效果的小程序,心血来潮想做下儿时的经典游戏----贪吃蛇.由于时间有限,只是简单地做了基本功能,有时间后再完善更多功能. 由于个人水平有限,可能代码有些地方可以改进.不足之处敬请指出. ...
- [Luogu] 计数
https://www.luogu.org/problemnew/show/P3130 #include <cstdio> #include <iostream> using ...
- 洛谷P4698 [CEOI2011]Hotel [贪心,二分,并查集]
题目传送门 Hotel 题目描述 你经营着一家旅馆,这家旅馆有 n 个房间,每个房间有维护费用和容量.其中第 i 个房间的维护费用为 ci,容量为 pi 人. 现在有 m 个订单,每个订单有两个参 ...
- 预处理、const、static与sizeof-#pragma pack的作用
1:有如下代码: #include <iostream.h> #pragma pack(1) struct test{ char c; short s1; short s2; int i; ...
- js判断是否联网
// navigator.onLine if (navigator.onLine){ //正常工作 console.log("在线状态............................ ...
- 转载: Windows下两种iocp实现的差距
转自:http://blog.csdn.net/oldworm/article/details/6171430 之前几天说过,因为经典iocp实现(以下简称经典实现)多个io线程绑定在一个iocp上, ...