一.内容回顾

  线程

  锁

    为什么有了GIL之后还需要锁

      多个线程同时操作全局变量还需要锁

      当出现'非原子性操作',例如+= -= *= /=

    l.append(l) 原子性操作

    a += 1  a= a+1

      tmp = a +1

      a = tmp

  死锁现象

    什么是死锁现象

      两个以上的线程争抢同一把锁

      其中一个线程获取到锁之后不释放

      另外的其他线程就都被锁住了

      比较容易出现问题的情况: 两把锁套在一起用了

      死锁现象的本质 :代码逻辑问题

  递归锁

    一把锁在同一个线程中acquire多次而不被阻塞

    如果另外的线程想要使用,必须release相同的次数

    才能释放锁给其他线程

  信号量

    控制几个线程同一时刻只能有n个线程执行某一段代码

    锁 + 计数器

  事件

    两件事情

    一件事情要想执行依赖于另一个任务的结果

  条件

    n个线程在某处阻塞

    由另一个线程控制这n个线程中有多少个线程能继续执行

  定时器

    规定某一个线程在开启之后的n秒之后执行

  队列\栈\优先级队列

    import queue

    线程之间数据安全

    多个线程get不可能同时取走一个数据,导致数据的重复获取

    多个线程put也不可能同时存入一个数据,导致数据的丢失

    队列 先进先出

    栈    先进后出

    优先级  优先级高的先出

  线程池

    concurrent.futrues

    ThreadPoolExcuter

    ProcessPoolExcuter

  submit 异步提交任务

  shutdown 等待池内任务完成

  result 获取进程函数的返回值

  map  异步提交任务的简便用法

  add_done_callback  回调函数

    进程 主进程执行

    线程

今日内容

  协程

  基础概念

  实现方式

  扩展模块

  第三方模块的安装

  

  IO模型

  IO多路复用

协程

  进程  计算机中最小的资源分配单位

  线程  计算机中能被CPU调度的最小单位

  线程是由操作系统创建的,开启和销毁仍然占用一些时间

  调度

    1.一条线程陷入阻塞之后,这一整条线程就不能再做其他事情了

    2.开启和销毁多条线程以及cpu在多条线程之间切换仍然依赖操作系统

  你了解协程

    了解

    协程(纤程,轻型线程)

    对于操作系统来说协程是不可见的,不需要操作系统调度

    协程是程序级别的操作单位

  协程效率高不高

    和操作系统本身没有关系,和线程也没有关系

    而是看程序的调度是否合理

  协程指的只是在同一条线程上能够互相切换的多个任务

  遇到io就切换实际上是我们利用协程提高线程工作效率的一种方式

  切换 + 状态保存  yield

import time
def consumer(res):
'''任务1:接收数据,处理数据'''
pass def producer():
'''任务2:生产数据'''
res=[]
for i in range(10000000):
res.append(i)
return res start=time.time()
# res=producer()
consumer(res) #写成consumer(producer())会降低执行效率
stop=time.time()
print(stop-start)
import time
def consumer():
while True:
res = yield def producer():
g = consumer()
next(g)
for i in range(10000000):
g.send(i)
start =time.time()
producer()
print(time.time() - start) # yield这种切换 就已经在一个线程中出现了多个任务,这多个任务之前的切换 本质上就是协程,consumer是一个协程,producer也是一个协程
# 单纯的切换还会消耗时间
# 但是如果能够在阻塞的时候切换,并且多个程序的阻塞时间共享,协程能够非常大限度的提高效率
# greenlet  协程模块 在多个任务之间来回切换
import time
from greenlet import greenlet def play():
print('start play')
g2.switch() # 开关
time.sleep(1)
print('end play')
def sleep():
print('start sleep')
time.sleep(1)
print('end sleep')
g1.switch()
g1 = greenlet(play)
g2 = greenlet(sleep)
g1.switch() # 开关
start play
start sleep
end sleep
end play

gevent

gevent.spawn()”方法会创建一个新的greenlet协程对象,并运行它。”
gevent.joinall()”方法会等待所有传入的greenlet协程运行结束后再退出,
这个方法可以接受一个”timeout”参数来设置超时时间,单位是秒。
# gevent 基于greenlet实现的,多个任务交给gevent管理,遇到IO就使用greenlet进行切换
import time
import gevent
def play(): # 协程1
print(time.time())
print('start play')
gevent.sleep(1)
print('end play')
def sleep(): # 协程2
print('start sleep')
print('end sleep')
print(time.time()) g1 = gevent.spawn(play)
g2 = gevent.spawn(sleep)
# g1.join()
# g2.join() # 精准的控制协程任务,一定是执行完毕之后join立即结束阻塞
gevent.joinall([g1,g2])
from gevent import monkey;monkey.patch_all()
# 把下面所有的模块中的阻塞都打成一个包,然后gevent就可以识别这些阻塞事件了
import time
import gevent
def play(): # 协程1
print(time.time())
print('start play')
time.sleep(1)
print('end play')
def sleep(): # 协程2
print('start sleep')
time.sleep(1)
print('end sleep')
print(time.time()) g1 = gevent.spawn(play)
g2 = gevent.spawn(sleep)
gevent.joinall([g1,g2])
import time
from gevent import monkey;monkey.patch_all()
from urllib.request import urlopen
import gevent
url_lst = ['https://www.python.org/','https://www.yahoo.com/','https://github.com/'] def get_page(url):
ret = urlopen(url).read().decode('utf-8')
return ret
start = time.time()
g_l = []
for url in url_lst:
g = gevent.spawn(get_page,url)
g_l.append(g) gevent.joinall(g_l)
print(time.time()-start)#2.8369998931884766

socket_server

from gevent import monkey;monkey.patch_all()
import socket
import gevent def talk(conn):
while True:
msg = conn.recv(1024).decode()
conn.send(msg.upper().encode()) sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen() while True:
conn,addr = sk.accept()
gevent.spawn(talk,conn)

socket_server

import socket
import threading
def task():
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
sk.send(b'hello')
print(sk.recv(1024)) for i in range(500):
threading.Thread(target=task).start()

总结

# 协程
# 一条线程在多个任务之间相互切换
# 数据安全的
# 不能利用多核
# 能够规避一个线程上的IO阻塞 # 一条线程能够起500个协程
# 4c的机器
# 5个进程
# 每一个进程20个线程
# 每一个线程500个协程
# 5*20*500 = 50000

IO模型
网络IO模型

阻塞IO 之前写的所有的socket recv阻塞  recvfrom accept

非租塞IO 能实现并发,浪费资源,并且麻烦

from socket import *
s=socket(AF_INET,SOCK_STREAM)#socket()是一个函数,创建一个套接字,AF_INET 表示用IPV4地址族,SOCK_STREAM 是说是要是用流式套接字
s.bind(('127.0.0.1',8080))
s.listen(5)
s.setblocking(False) #设置socket的接口为非阻塞
conn_l=[] # 所有通话连接的列表
del_l=[] #
# 1s 10000行代码 9998行都是异常处理 白白消耗了系统资源
while True:
try:
conn,addr=s.accept() # 如果有人链接我 我就直接通过连接 如果没人链接我 我就报错
conn_l.append(conn) # 如果有人连我,就获取到一个conn,并且把这个conn添加到conn_l
except BlockingIOError:
for conn in conn_l: # [conn1,conn2]
try:
data=conn.recv(1024) #尝试接收每一个和我连接的人的消息
if not data: # 如果对方已经断开连接了
del_l.append(conn) # 就把这个连接添加到del_l中
continue
conn.send(data.upper()) # 对每一个发送给我的信息进行回复
except BlockingIOError: # 如果某个conn并没有消息来就会报错,被这个异常处理
pass
except ConnectionResetError: # 如果对方已经断开连接了
del_l.append(conn) for conn in del_l: # 对于已经断开连接的这些conn [conn1]
conn_l.remove(conn) # 从conn_l中移除这个连接
conn.close() # 关闭这个连接
del_l=[] # 将del_l置空
# IO多路复用
# 操作系统提供给你的
# 对于你的程序来说 : 是一个代理
# 帮助你监听所有的通信对象,是否有数据来到操作系统中
# 一旦有 就通知你
# 你再根据通知来接收相应的数据
# 你不需要一直循环着问每一个对象是否有信息来,而是阻塞等待,任意一个对象有信息来,我就接收
import select
# io多路复用有好几种机制 : select poll epoll
# 多个io对象,多个conn,sk
# 一个conn占着一条网络连接的路
# 多个conn占着多条路
# 多个conn复用同一个线程的操作
# from socket import *
# import select
#
# s=socket(AF_INET,SOCK_STREAM)
# s.bind(('127.0.0.1',8081))
# s.listen(5)
# s.setblocking(False) #设置socket的接口为非阻塞
# read_l=[s,]
# while True:
# r_l,w_l,x_l=select.select(read_l,[],[])
# print(r_l,read_l)
# for ready_obj in r_l:
# if ready_obj == s:
# conn,addr=ready_obj.accept() #此时的ready_obj等于s
# read_l.append(conn)
# else:
# try:
# data=ready_obj.recv(1024) #此时的ready_obj等于conn
# if not data:
# ready_obj.close()
# read_l.remove(ready_obj)
# continue
# ready_obj.send(data.upper())
# except ConnectionResetError:
# ready_obj.close()
# read_l.remove(ready_obj) # 异步IO # socketserver
# selectors模块 + threading模块实现的

非阻塞io的client

#客户端
from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('127.0.0.1',8081)) while True:
msg=input('>>: ')
if not msg:continue
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data.decode('utf-8'))

day43 Pyhton 并发编程06的更多相关文章

  1. 并发编程 06—— CompletionService :Executor 和 BlockingQueue

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

  2. Python并发编程06 /阻塞、异步调用/同步调用、异步回调函数、线程queue、事件event、协程

    Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件event.协程 目录 Python并发编程06 /阻塞.异步调用/同步调用.异步回调函数.线程queue.事件 ...

  3. Java并发编程(06):Lock机制下API用法详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Lock体系结构 1.基础接口简介 Lock加锁相关结构中涉及两个使用广泛的基础API:ReentrantLock类和Condition接 ...

  4. day38 Pyhton 并发编程

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

  5. day41 Pyhton 并发编程04

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

  6. day42 Pyhton 并发编程05

    一.内容回顾 # 线程 # 正常的编程界: # 进程 # 计算机中最小的资源分配单位 # 数据隔离 # 进程可以独立存在 # 创建与销毁 还有切换 都慢 给操作系统压力大 # 线程 # 计算机中能被C ...

  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. 关于pom.xml文件中配置jquery,以及如何在jsp中引入

    pom.xml <!-- 对jquery的支持 --> <dependency> <groupId>org.webjars.bower</groupId> ...

  2. 正则表达式在Java中应用的三种典型场合:验证,查找和替换

    正则式在编程中常用,总结在此以备考: package regularexp; import java.util.regex.Matcher; import java.util.regex.Patter ...

  3. C#中部分重点前端设置问题

    背景 在工作及学习过程中经常会遇到一些奇怪的需求,这里便会记录我遇到的奇怪需求及解决方法. 内容 一.动态设置页面标题 1.前端设置 JS代码: document.title="这是一个标题 ...

  4. Linux:crond(crontab)定时任务

    一..定义 Crond 是linux系统中用来定期执行命令或指定程序任务的一种服务或者软件.一般在安装完系统时,crond会默认存在. crond默认每分钟会检查系统中是否有需要执行的定时任务.如果有 ...

  5. Lambda表达式看这篇基本就够用了

    本文讯] 2020.05.08  polo  写博不易,尊重知识! Lambda  是java8 引入的一个新特性,闭包,又叫函数式接口,下面介绍下,常用的lambda表达式方式: 所谓的将函数作为一 ...

  6. ansible中定义变量的若干方法

    Ansible支持十几种定义变量的方式 根据优先级排序的定义方式: Inventory变量 Host Facts变量 Playbook变量 Playbook提示变量 变量文件 命令行变量 1.Inve ...

  7. 解Bug之路-串包Bug

    解Bug之路-串包Bug 笔者很热衷于解决Bug,同时比较擅长(网络/协议)部分,所以经常被唤去解决一些网络IO方面的Bug.现在就挑一个案例出来,写出分析思路,以飨读者,希望读者在以后的工作中能够少 ...

  8. [LeetCode]198. 打家劫舍(DP)

    题目 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定一个 ...

  9. algorithm入门算法中的常见问题

    KMP算法(next数组) 二分查找(非递归) /** * 二分查找(非递归) * @param arr 从小到大的排序数组 * @param target 目标查找值 * @return */ pu ...

  10. python的循环结构

    遍历循环 计数循环(N次)/(特定次)/字符串遍历循环 列表遍历循环/文件遍历循环......字典遍历循环等等 例子--计数循环 输出从1到6的整数,以2为步长 字符串遍历循环 列表遍历循环 文件遍历 ...