一.内容回顾

# 线程
# 正常的编程界:
# 进程
# 计算机中最小的资源分配单位
# 数据隔离
# 进程可以独立存在
# 创建与销毁 还有切换 都慢 给操作系统压力大
# 线程
# 计算机中能被CPU调度的最小单位
# 同一个进程中的多个线程资源共享
# 线程必须依赖进程存在
# 创建与销毁 还有切换 都比进程快很多
# Cpython解释器下
# GIL 全局解释器锁
# 保证了同一时刻下只有一个线程可以被CPU操作 # threading模块
# 创建子线程 Thread类
# start 开启子线程
# join 阻塞等待子线程结束
# setDeamon 设置守护线程
# 会等待主线程结束(包含所有非守护的子线程)之后守护线程才结束
# currentthread,enumerate,activecount
# 查看当前线程,所有的线程对象组成的列表,列表的长度
# from threading import Thread,currentThread
# def func():
# print(currentThread())
# for i in range(10):
# Thread(target=func).start()

今日内容

# 1.锁   ****
# 互斥锁
# 死锁现象
# 递归锁
# 2.其他模型 **
# 信号量
# 事件
# 条件
# 定时器
# 3.线程队列 ****
# 4.线程池模块 ****
# 锁是用来做什么的?
# 保证数据的安全的
# GIL是干什么的?
# 全局解释器锁线程
# 有了GIL还要锁干啥?
# 有了GIL还是会出现数据不安全的现象,所以还是要用锁
# import time
# from threading import Thread,Lock
# n = 100
# def func(lock):
# global n
# # n -= 1
# with lock:
# tmp = n-1 # n-=1
# time.sleep(0.1)
# n = tmp
#
# if __name__ == '__main__':
# l = []
# lock = Lock()
# for i in range(100):
# t = Thread(target=func,args=(lock,))
# t.start()
# l.append(t)
# for t in l:t.join()
# print(n)
dis模块使用
import dis
n = 1
def func():
n = 100
n -= 1 dis.dis(func) # 会出现线程不安全的两个条件
# 1.是全局变量
# 2.出现 += -=这样的操作 # 列表 字典
# 方法 l.append l.pop l.insert dic.update 都是线程安全的
# l[0] += 1
# d[k] += 1
死锁现象
# 科学家吃面问题
import time
from threading import Thread,Lock
# noodle_lock = Lock()
# fork_lock = Lock()
# 死锁不是时刻发生的,有偶然的情况整个程序都崩了
# 每一个线程之中不止一把锁,并且套着使用
# 如果某一件事情需要两个资源同时出现,那么不应该将这两个资源通过两把锁控制
# 而应看做一个资源
import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock(
def eat1(name):
noodle_lock.acquire()
print('%s拿到面条了'%name)
fork_lock.acquire()
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name) def eat2(name):
fork_lock.acquire()
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()
alex拿到面条了
alex拿到叉子了
alex开始吃面
alex放下叉子了wusir拿到叉子了
alex放下面了太白拿到面条了
发生了死锁
import time
from threading import Thread,Lock
lock = Lock()
def eat1(name):
lock.acquire()#只有一个锁,把资源都锁在一起
print('%s拿到面条了'%name)
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
lock.release()
print('%s放下叉子了' % name)
print('%s放下面了' % name) def eat2(name):
lock.acquire()
print('%s拿到叉子了' % name)
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
lock.release()
print('%s放下面了' % name)
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()
# 先临时解决
# 然后再找到死锁的原因,再去修改
from threading import RLock,Lock,Thread
# 互斥锁
# 无论在相同的线程还是不同的线程,都只能连续acquire一次
# 要想再acquire,必须先release
# 递归锁
# 在同一个线程中,可以无限次的acquire
# 但是要想在其他线程中也acquire,
# 必须现在自己的线程中添加和acquire次数相同的release
rlock = RLock()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
print('锁不住')
锁不住
lock = Lock()
lock.acquire()
print('1')
lock.acquire()
print('2')#不能打印2
rlock = RLock()
def func(num):
rlock.acquire()
print('aaaa',num)
rlock.acquire()
print('bbbb',num)
rlock.release()
rlock.release() Thread(target=func,args=(1,)).start()
Thread(target=func,args=(2,)).start()
aaaa 1
bbbb 1
aaaa 2
bbbb 2
import time
noodle_lock = fork_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print('%s拿到面条了'%name)
fork_lock.acquire()
print('%s拿到叉子了'%name)
print('%s开始吃面'%name)
time.sleep(0.2)
fork_lock.release()
print('%s放下叉子了' % name)
noodle_lock.release()
print('%s放下面了' % name) def eat2(name):
fork_lock.acquire()
print('%s拿到叉子了' % name)
noodle_lock.acquire()
print('%s拿到面条了' % name)
print('%s开始吃面' % name)
time.sleep(0.2)
noodle_lock.release()
print('%s放下面了' % name)
fork_lock.release()
print('%s放下叉子了' % name) Thread(target=eat1,args=('alex',)).start()
Thread(target=eat2,args=('wusir',)).start()
Thread(target=eat1,args=('太白',)).start()
Thread(target=eat2,args=('宝元',)).start()

alex拿到面条了

alex拿到叉子了

alex开始吃面

alex放下叉子了

alex放下面了

wusir拿到叉子了

wusir拿到面条了

wusir开始吃面

wusir放下面了

wusir放下叉子了

太白拿到面条了

太白拿到叉子了

太白开始吃面

太白放下叉子了

太白放下面了

宝元拿到叉子了

宝元拿到面条了

宝元开始吃面

宝元放下面了

宝元放下叉子了

信号量

import time
from threading import Semaphore,Thread def func(name,sem):
sem.acquire()
print(name,'start')
time.sleep(1)
print(name,'stop')
sem.release() sem = Semaphore(5)
for i in range(20):
Thread(target=func,args=(i,sem)).start()
# 信号量和池
# 进程池
# 有1000个任务
# 一个进程池中有5个进程
# 所有的1000个任务会多次利用这五个进程来完成任务
# 信号量
# 有1000个任务
# 有1000个进程/线程
# 所有的1000个任务由于信号量的控制,只能5个5个的执行

事件

from threading import Event
# 事件
# wait() 阻塞 到事件内部标识为True就停止阻塞
# 控制标识
# set
# clear
# is_set # 连接数据库
import time
import random
from threading import Thread,Event
def connect_sql(e):
count = 0
while count < 3:
e.wait(0.5)
if e.is_set():
print('连接数据库成功')
break
else:
print('数据库未连接成功')
count += 1 def test(e):
time.sleep(random.randint(0,3))
e.set() e = Event()
Thread(target=test,args=(e,)).start()
Thread(target=connect_sql,args=(e,)).start()

条件

# wait      阻塞
# notify(n) 给信号
# 假如现在有20个线程
# 所有的线程都在wait这里阻塞
# notify(n) n传了多少
# 那么wait这边就能获得多少个解除阻塞的通知 # notifyall
# acquire
# release import threading def run(n):
con.acquire()
con.wait()
print("run the thread: %s" % n)
con.release() if __name__ == '__main__': con = threading.Condition()
for i in range(10):
t = threading.Thread(target=run, args=(i,))
t.start() while True:
inp = input('>>>')
if inp == 'q':
break
con.acquire()
con.notify(int(inp))
con.release()
print('****') # 设置某个条件
# 如果满足这个条件 就可以释放线程
# 监控测试我的网速
# 20000个任务
# 测试我的网速 /系统资源
# 发现系统资源有空闲,我就放行一部分任务

定时器

from threading import Timer

def func():
print('执行我啦') t = Timer(3,func)
# 现在这个时间点我不想让它执行,而是预估一下大概多久之后它执行比较合适
t.start()
print('主线程的逻辑')

队列

import queue

# 线程队列 线程之间数据安全
q = queue.Queue(1)
# 普通队列
q.put(1)
print(q.get())
try:
q.put_nowait(2)
except queue.Full:
print('您丢失了一个数据2')
print(q.get_nowait()) # 如果有数据我就取,如果没数据不阻塞而是报错
# 非阻塞的情况下
q.put(10)
print(q.get(timeout=2))
1
2
10
# 算法里 栈
lfq = queue.LifoQueue() # 栈
lfq.put(1)
lfq.put(2)
lfq.put(3)
print(lfq.get())
print(lfq.get())
print(lfq.get())
3
2
1
# 优先级队列,是根据第一个值的大小来排定优先级的
# ascii码越小,优先级越高
q = queue.PriorityQueue()
q.put((2,'a'))
q.put((0,'c'))
q.put((1,'b')) print(q.get()) # 线程+队列 实现生产者消费者模型

线程池

def func(num):
print('in %s func'%num,currentThread())
time.sleep(random.random())
return num**2 tp = ThreadPoolExecutor(5)
ret_l = []
for i in range(30):
ret = tp.submit(func,i)#运行时只有5个线程运行
ret_l.append(ret)
for ret in ret_l:
print(ret.result())
import time
import random
from threading import currentThread
from concurrent.futures import ThreadPoolExecutor as Pool import os
def func(num):
print('in %s func'%num,currentThread())
# print('in %s func'%num,os.getpid())
time.sleep(random.random())
return num**2
if __name__ == '__main__':
# tp = ThreadPoolExecutor(5)
tp = Pool(5)
ret_l = []
for i in range(30):
ret = tp.submit(func,i)
ret_l.append(ret)
tp.shutdown() # close + join
for ret in ret_l:
print(ret.result())
# 创建一个池
# 提交任务 submit
# 阻塞直到任务完成(close + join) shutdown
# 获取结果 result
# 简便用法 map
# 回调函数 add_done_callback
# 简便用法 map
import os
def func(num):
print('in %s func'%num,currentThread())
# print('in %s func'%num,os.getpid())
time.sleep(random.random())
return num**2
if __name__ == '__main__': # tp = ThreadPoolExecutor(5)
tp = Pool(5)
ret = tp.map(func,range(30))
for i in ret:
print(i)
# 回调函数 add_done_callback
def func1(num):
print('in func1 ',num,currentThread())
return num*'*' def func2(ret):
print('--->',ret.result(),currentThread())
tp = Pool(5)
print('主 : ',currentThread())
for i in range(10):
tp.submit(func1,i).add_done_callback(func2)
# 回调函数收到的参数是需要使用result()获取的
# 回调函数是由谁执行的? 主线程
# 相关概念
# 进程
# 线程
# GIL
# 很多模型
# 进程 锁(递归锁 互斥锁)\池(cpu的1-2倍)\队列
# 线程 锁(递归锁 互斥锁)\池(cpu个数的5倍)\队列 其他模型

day42 Pyhton 并发编程05的更多相关文章

  1. 并发编程 05—— Callable和Future

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  2. Python并发编程05 /死锁现象、递归锁、信号量、GIL锁、计算密集型/IO密集型效率验证、进程池/线程池

    Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密集型效率验证.进程池/线程池 目录 Python并发编程05 /死锁现象.递归锁.信号量.GIL锁.计算密集型/IO密 ...

  3. Java并发编程(05):悲观锁和乐观锁机制

    本文源码:GitHub·点这里 || GitEE·点这里 一.资源和加锁 1.场景描述 多线程并发访问同一个资源问题,假如线程A获取变量之后修改变量值,线程C在此时也获取变量值并且修改,两个线程同时并 ...

  4. day38 Pyhton 并发编程

    # 网络编程 # arp协议 : # 1.这是一个通过ip找mac地址的协议 # 2.由于有了socket,用户在使用网络的时候,只需要关心对方用户的ip地址就可以了 # 3.如果用户即将和这个ip进 ...

  5. day41 Pyhton 并发编程04

    内容回顾 socket 最底层的网络通信 所有的网络通信都是基于socket     进程 什么是进程? 是操作系统的发展过程中,为了提高cpu的利用率,在操作系统同时运行多个程序的时候,为了数据的安 ...

  6. day43 Pyhton 并发编程06

    一.内容回顾 线程 锁 为什么有了GIL之后还需要锁 多个线程同时操作全局变量还需要锁 当出现'非原子性操作',例如+= -= *= /= l.append(l) 原子性操作 a += 1  a= a ...

  7. day40 Pyhton 并发编程03

    一.内容回顾 进程是计算机中最小的资源分配单位 进程与进程之间数据隔离,执行过程异步 为什么会出现进程的概念? 为了合理利用cpu,提高用户体验 多个进程是可以同时利用多个cpu的,可以实现并行的效果 ...

  8. day39 Pyhton 并发编程02 后

    一.开启子进程的另一种方式 import os from multiprocessing import Process class MyProcess(Process): def __init__(s ...

  9. day39 Pyhton 并发编程02

    一.内容回顾 并发和并行的区别 并发 宏观上是在同时运行的 微观上是一个一个顺序执行 同一时刻只有一个cpu在工作 并行 微观上就是同时执行的 同一时刻不止有一个cpu在工作 什么是进程 一个运行中的 ...

随机推荐

  1. Redis windows版安装测试

    1.下载 下载地址是 https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100 ,我选择的是Redis-x64-3.2.10 ...

  2. java输出1-100之间的数并求和for+while+do while实现

    public static void main(String args[]) {//do while int sum = 0; //当前之和 int i = 1; //加数 do { if (i%2= ...

  3. 突然虚拟机无法联网解决办法,且报错Failed to start LSB: Bring up/down

    使用sudo service network restart去启动网络时起不来 使用systemctl status network.service查看网络状态也是failed,且报错Failed t ...

  4. C#开发PACS医学影像处理系统(十一):Dicom影像挂片协议

    通俗点说,挂片协议可以看作整个系统的一个相对复杂一点的配置文件,可以用JSON或XML格式来读取与保存, 另外,可以制作一个独立的exe配置程序来管理这些挂片协议. 假设配置了CT的挂片协议的右键菜单 ...

  5. sql分页存储过程,带求和、排序

    创建存储过程: CREATE PROCEDURE [dbo].[sp_TBTest_Query] ( @PageSize INT, --每页多少条记录 @PageIndex INT = 1, --指定 ...

  6. 硬核看房利器——Web 全景的实现

    作者:凹凸曼 - EC 疫情期间,打破社交距离限制的交互模式被推向前台,为不少行业的传统交易提供了想象的空间. 疫情时期,房地产租售业受到的冲击无疑是巨大的,由于人口流动的限制,需求量大幅减少,无法现 ...

  7. 【小白学PyTorch】12 SENet详解及PyTorch实现

    文章来自微信公众号[机器学习炼丹术].我是炼丹兄,有什么问题都可以来找我交流,近期建立了微信交流群,也在朋友圈抽奖赠书十多本了.我的微信是cyx645016617,欢迎各位朋友. 参考目录: @ 目录 ...

  8. (jvm调优)一、linux内存查看命令

    转载自https://blog.csdn.net/dongzhongyan/article/details/80067796 开始学习服务器性能查看以及调优 1.整体情况查看(任务管理器):top 第 ...

  9. 容器云平台No.4~kubernetes 服务暴露之Ingress

    这是容器云平台第四篇,接上一篇继续, 首先kubernetes服务暴露有如下几种方式: NodePort Loadbalance ClusterIP Ingress 本文紧贴第一篇架构图,只介绍Ing ...

  10. 爬虫必看,每日JS逆向之爱奇艺密码加密,今天你练了吗?

    友情提示:优先在公众号更新,在博客园更新较慢,有兴趣的关注一下知识图谱与大数据公众号,本次目标是抠出爱奇艺passwd加密JS代码,如果你看到了这一篇,说明你对JS逆向感兴趣,如果是初学者,那不妨再看 ...