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个数来达到效率平衡
View Code

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()
View Code

 

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个
    #
View Code

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.  明天默写和线程相关的
View Code

 

posted @ 2019-04-17 11:23  learnacode  阅读(178)  评论(0编辑  收藏  举报