day 34

时间:2023-03-09 17:14:51
day 34

1 .内容回顾

#__author : 'liuyang'
#date : 2019/4/17 0017 上午 9:01
# 利大于弊,则做之
# 会死于斯,则不去
# 2个 人 晚上 5个题 面试题
# 今晚 7点 考试题
# 五一之前 要考试
#其它内容(40%) 网编并发数据库(60%) #锁
#互斥锁
#能够保护数据的安全性
#保证对于数据的修改操作同一时刻多个进程只有一个进程执行
#进程数据不安全:同时修改文件/数据库/其它共享资源的数据 # 队列---实现了进程之间的通信(IPC) #进程队列 ----进程安全
#从mutltiprocessing 导入Queue
#q = Queue()
#put/get
# 基于管道+管道 ,管道 进程不安全
# 管道 基于文件级别的socket 实现的 import queue
from multiprocessing import Queue
# 生产者消费模型
# put get 两个阻塞方法
# put_nowait(丢数据)/ get_nowait 非阻塞方法
q = Queue(5) #队列里有五个
q.put(1)
q.put(1)
q.put(1)
q.put(1)
q.put(1)
print('_____________')
try :
q.put_nowait(1) #也传一个
except queue.Full:
# 存在这里
pass
# q.put(1)
print('______')
# q.put(1)
print('__')
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get()) # print(q.get())
# print(q.get())
# print(q.get()) try :
print(q.get_nowait())
except queue.Empty:
pass # 网页版的 qq
# sereve 端 djiong 写的
# 信息一直没有 一直夯在这 于是 用get_nowait() 没数据立刻返回
# 隔个0.5秒 再返回来查看 # 生产者 消费者 模型
# 达到效率平衡
# 一个生产数据和消费数据的完整的流程解耦解耦成两个部分:生产和消费
#由于生产速度和消费速度不一致,所以需要我们调整生产者和消费者额d个数来达到效率平衡

2.今日内容

#1 互斥锁
#2 进程之间的数据共享
#关于数据安全的问题
#3 进程池
#from multiprocessing import Pool
# 事件\信号量\管道
# 4 线程的概念(面试的重点)
# 5 认识线程模块

3.什么是互斥锁

# 在多个进程中 或者一个进程中

# 有acquire()acquire()就阻在那里了

#__author : 'liuyang'
#date : 2019/4/17 0017 上午 9:27
# from multiprocessing import Lock
# #1 互斥锁:不能在同一个进程内,‘也’有锁的竞争关系
# # 在同一个进程中连续acquire多次会产生死锁
# lock = Lock()
# lock.acquire() #拿走钥匙
# print(1)
# lock.acquire() #被拿走了又想要钥匙 卡住 #互斥
# print(2)
# # lock.release() #没还钥匙 卡在第一个开锁那
# lock.release()
# lock.release()

4.数据共享(进程内可以但是不大需要)

# 本来是数据隔离的

# 加上Manager就可以分享了

#__author : 'liuyang'
#date : 2019/4/17 0017 上午 9:35
#数据共享几乎不用
# 数据共享: 可以, Manager 但是不安全
# 可以 安全 加锁 from multiprocessing import Process,Manager,Lock
def func(dic):
dic['count'] -= 1 # 数据不共享 正常情况下数据隔离 子进程改
if __name__ == '__main__':
lock = Lock()
m = Manager()
dic = m.dict({'count':100})
p_l = []
for i in range(100):
p = Process(target=func,args=(dic,lock))
p.start()
p_l.append(p)
for p in p_l : p.join()
print(dic) #{'count': 0} 性能越好 越不得零 # 100 减 100次 1 这么慢? 不是减操作造成的
# 慢是因为 开100个进程 所以慢 开和管理 销毁进程拖慢了程序的运行效率 # 为什么在这里出现了数据不安全的现象?
# 正常不会数据共享 隔离 肯定通过socket 文本或者网络传过来的
# (不丢失)性能快的时候,比如两个 子进程同时对一样的值操作了,返回的一样的值 #什么情况会出现数据不安全:Manager 类当中对字典/列表 += -= *= /=
#添加值 不会
#如何解决 : 加锁 # 修改的 异步 性能高了会出错对同一个进行操作 #加锁同步安全
# 查看的 异步快 # cpu个数 最多起cpu*2个
#

5.多线程

cpython解释器内置的 GIL锁,同步

为了数据安全

解释性语言(一边解释一边编译 解释的字节码 无序 所以操作造成异步操作 数据不安全)

编译型语言可以实现多进程

#__author : 'liuyang'
#date : 2019/4/17 0017 上午 10:18
# 线程是进程中的一个单位
# 进程是计算机中最小的资源分配单位
# 线程是计算机中被CPU调度的最小单位 # 开启进程 关闭进程 切换进程都需要时间
# 你的电脑的资源还是优先的
# 开启过多的进程会导致你的计算机崩溃 # count_cpu*2 = 8 #4 核
# 同时对8个客户端服务
# qps 每秒的请求数 2W # 2000/8 = 250 台机器 # 进程: 数据隔离的
#ftp server端
#qq server端(不用隔离,本来就不传输,得写了才传)
# 并发: 同一时刻能同时接受多个客户端的请求
# 进程有大 有数据隔离 开多了还不行 (有的不需要隔离,还要ipc传输过来、) #线程:
# 轻型进程 轻量级的进程
# 在同一个进程中的多个线程是可以共享一部分数据的
# 线程的开启\销毁\切换都比进程要高级很多 #1.多个进程可不可以利用多核(多个CPU)
#2.多个线程可不可以利用多核(多个CPU)
# 都可以 # 多进程和多线程之间的区别
#进程 数据隔离 开销大 (必须数据隔离是才会进程)
#线程 数据共享 开销小 # python 当中的多线程
# Cpython 解释器 有一个GIL锁 (怕麻烦 要不太多修改的)
# # (解释性语言) 编译 --》字节码(bytes) 没法正常排序的-->机器码(0101)
# python 代码机器语言
from dis import dis
def func():
a = []
a.append(1)
dis(func)
'''
42 0 BUILD_LIST 0
2 STORE_FAST 0 (a) 43 4 LOAD_FAST 0 (a)
6 LOAD_ATTR 0 (append)
8 LOAD_CONST 1 (1) #加载他们几个存在内存里
10 CALL_FUNCTION 1 #调用
12 POP_TOP
14 LOAD_CONST 0 (None)
16 RETURN_VALUE''' #默认返回空
# 两个程序在两个cpu上同时触发,就可能造成数据不安全
# python 解释器(自动加锁) 同一时刻 只能有一个线程执行(单线程) # 解释性语言(python,php) 都不能多个程序(线程)访问多个cpu #(异步执行无序)所以数据不安全
# 编译型语言(c,java) 都能多个程序(线程)访问多个cpu # GIL 锁 历史遗留问题(python诞生时没有多核)
#线程中的状态 就不如编译型语言 那么完美 # python 当中的多线程(不是python的锅,可以解决的,没必要)
# 不能访问多个cpu
# 是Cpython(解决不了高运算) 解释器导致的 #不同的工具不同的功能
#每个工具都不是万能的
# GIL = 全局解释器锁 导致了同一时刻只能有一个线程访问cpu
# pypy 没有GIL锁 Jpython 解释成java 可以多线程访问多核的 (但是他们的执行效率慢) # 研究pypy(和cpython速度相近了) 不如直接研究 go
# go 的执行效率 和 c相近了 #利用 多核意味着 多个CPU可以同时计算线程中的代码 # IO 操作
#accept负责从网络上读取数据
#open() 调用操作系统的指令 0.9ms的时间 (cpu执行450万条指令(在阻塞))
#read #7个指令 一行代码 50w/7 7w条 python 代码 千分之一秒 执行的 # 分布式\多进程
#大量的计算 可以开 多进程 进多核 高额业务 # ftp 这样的大部分都是网络和进程都无关
# web 框架 #大部分时间 都是金阻塞 io呢 文件呢 网络呢 没大进cpu进行
#所以单进程多线程就够了
#Django flask tornado twistwed scrapy sanic
#都 并发 多线程 没有用进程 # 解释性和 编译型 的 因为一边翻译 一边编译 不如 直接汉语好 英语放过来

  

6.python代码实现  thread(进程)

#__author : 'liuyang'
#date : 2019/4/17 0017 上午 11:34
# 利 = 1
# 弊 = 2
# do = 'do'
# if 利 > 弊:
# do
#
import threading
# threading 和 multtiprocessing
# 先有的threading模块
#没有池的功能
#multiprocessing 完全模仿threading 模块完成的
#实现了池的功能
#concurrent.futures
#实现了线程池\进程池 # import os
# import time
# from threading import Thread
# def func(i): #子线程
# time.sleep(1) #阻塞了之后 cpu就绪 执行就不在控制范围内 了所以不按顺序
# print('in func',i, os.getpid())
#
# print('in main',os.getpid())
# #一个线程的时间开启和管理的时间不是固定的 开的时候有可能cpu很闲
# #直接执行了
#
# for i in range(20): #并发 #异步不是一起执行
# Thread(target=func,args=(i,)).start()
#func() #同步20 秒 20倍差别
#in main 4676
# in func 4676
# 在一个进程里 # if __name__ =='__main__': #多个线程都是 共享的 没有import没有导入
# 不会被执行 所以 不用
# 在线程部分不需要通过import来为新的线程获取代码
# 因为新的线程和之前的主线程共享同一段代码
# 不需要import 也就不存在 子进程中有重复了一次 # 开销 # 进程和线程的代码管理 是一样的 因为都是开和关 没必要有差距
# 数据隔离
#
# from multiprocessing import Process
# from threading import Thread
# import time
# def func(a):
# a += 1
# if __name__ =='__main__':
# start = time.time()
# t_l = []
#
# for i in range(100):
# t = Thread(target=func,args=(i,))
# t.start()
# t_l.append(t)
# for t in t_l : t.join() # 确保前面都执行完
# print('thread',time.time() - start )
#
# start = time.time()
# t_l = []
#
# for i in range(100):
# t = Process(target=func, args=(i,))
# t.start()
# t_l.append(t)
# for t in t_l: t.join() # 确保前面都执行完
# print('process',time.time() - start)
#
# #t 0.0870048999786377
# # p 7.8074469566345215
# 100倍 开进程倍 # 多个线程之间的全局变量是共享的
#
# from multiprocessing import Process
# from threading import Thread
# import time
# tn = 0
# def func(a):
# global tn
# tn += 1
# if __name__ =='__main__':
# start = time.time()
# t_l = []
#
# for i in range(100):
# t = Thread(target=func,args=(i,))
# t.start()
# t_l.append(t)
# for t in t_l : t.join() # 确保前面都执行完
# print('thread',time.time() - start )
# print(tn)
#
# # 进程之间数据隔离
# pn = 0 # 这里定义了 所以不报错
# def func(a):
# global pn
# pn += 1
#
# if __name__ == '__main__':
#
# start = time.time()
# t_l = []
#
# for i in range(100):
# t = Process(target=func, args=(i,))
# t.start()
# t_l.append(t)
# for t in t_l: t.join() # 确保前面都执行完
# print('process',time.time() - start)
# print(pn) # 线程中的几个替他方法
from threading import Thread,currentThread #线程对象
import os
def func():
t = currentThread() #线程属于哪个id的
print(t.name,t.ident,os.getpid())
# print(currentThread(),os.getpid()) tobj = Thread(target=func)
tobj.start()
print('tobj:',tobj)
# print(currentThread(),os.getpid())
'''
Thread-1 9224 9612
<_MainThread(MainThread, started 4108)> 9612
<Thread(Thread-1, started 9224)> 9612
'''
'''
Thread-1 8800 9588 #巧了 异步一样
tobj: <Thread(Thread-1, stopped 8800)>''' lst = [1,2,3,4,5,6,7,8,9,10]
#按照顺序把列表中的每一个元素都计算一个平方
#使用多线程方式
# #并且将结果按照顺序返回
from threading import Thread #线程对象
import time
import random
dic = {}
def func(i):
t = currentThread()
time.sleep(random.random())
dic[t.ident] = i**2
t_l = []
for i in range(1,11):
t = Thread(target=func, args=(i,))
t.start()
t_l.append(t)
for t in t_l:
t.join() # 确保前面都执行完
print(dic[t.ident])
print(dic) #{7936: 81, 6056: 4, 9344: 49, 10188: 9, 6648: 100, 7264: 64, 4072: 16, 9924: 36, 8796: 1, 7216: 25}
#这不是 按顺序添加的 只是显示是顺序的 添加是按顺序的 # from threading import active_count
# # 返回当前正在工作的线程
# from threading import Thread #线程对象
# import time
# import random
# l = []
# def func(a):
# t = currentThread()
# time.sleep(random.random())
# for i in range(1,11):
# t = Thread(target=func, args=(i,))
# #t.start() 11 个 不start() 就不执行
# print(active_count()) #1 #只有一个主线程 # 线程有terminate 么?
#没有terminate 不能强制结束
#所有的子线程都会在执行完所有的任务之后结束 # 统计线程的id 统计正在执行的线程数 用法差不多 没有terminate # 1 . 通读博客 :操作系统 ,进程,线程
# 2 . 把课上的代码都搞明白
# 3. 多线程实现一个并发 tcp协议的socket_server
# 4. 明天默写和线程相关的