36-进程池线程池
开多线程实现并发的效率是高的,当用户没有那么多的时候,服务器是可以承受压力的
但是一定要以某种方式来设置并发数,让服务器能够实现稳定的运行,控制服务器的线程数
设置池,往里面放池的数量限制,进程池就是往进程池里放进程数,线程池就是往池里放线程数
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from multiprocessing import Process
import os
import time
import random
# 线程池和进程池的接口是一样的,那么什么时候用进程池,什么时候用线程池
# 池本质就是开进程和线程,本质没有区别
# 计算密集型,需要用多核的优势时候就要用进程池
# I/O密集型,不需要过多CPU资源的时候就要用线程池
 
 
def task(name):
    print('name is %s pid is %s'%(name, os.getpid()))
    time.sleep(random.randint(1,3))
 
 
if __name__ == '__main__':
    # 进程池最多装4个进程
    # pool = ThreadPoolExecutor(4)
    pool = ProcessPoolExecutor(4)
    for i in range(10):
        # 异步调用,提交完任务以后,不用等任务拿到结果,只负责任务做完
        pool.submit(task,'panda %s'%i)
    pool.shutdown()
    print('主线程')
 

37-异步调用与回调机制
提交任务的两种方式
1.同步调用
# 1.同步调用:提交完任务后,就等待任务执行完毕,拿到结果,再执行下一行代码
# 同步调用的结果就是串行执行的方式
import time
import random
from concurrent.futures import ThreadPoolExecutor
 
 
def la(name):
    print('%s is laing' % name)
    time.sleep(random.randint(1,3))
    res = random.randint(7,13)*"*"
    return {'name':name, 'res':res}
 
 
def weight(obj):
    name = obj['name']
    size = obj['res']
    print('%s is %s'%(name, size))
 
 
if __name__ == '__main__':
    pool = ThreadPoolExecutor(10)
    res1 = pool.submit(la, 'panda').result()
    weight(res1)
    res2 = pool.submit(la, 'zombie').result()
    weight(res2)
    res3 = pool.submit(la, 'boy').result()
    weight(res3)
2.异步调用
# 2.异步调用:提交完任务以后不在原地等待任务执行完毕,
import time
import random
from concurrent.futures import ThreadPoolExecutor
 
 
def la(name):
    print('%s is laing' % name)
    time.sleep(random.randint(1,3))
    res = random.randint(7,13)*"*"
    return {'name':name, 'res':res}
 
 
def weight(obj):
    obj = obj.result()
    name = obj['name']
    size = obj['res']
    print('%s is %s'%(name, size))
 
 
if __name__ == '__main__':
    pool = ThreadPoolExecutor(10)
    pool.submit(la, 'panda').add_done_callback(weight)
    pool.submit(la, 'zombie').add_done_callback(weight)
    pool.submit(la, 'boy').add_done_callback(weight)
 
 

38-进程池线程池小练习
from threading import Thread
from concurrent.futures import ThreadPoolExecutor
import requests
import time
 
def get(url):
    print('GET %s' % url)
    response = requests.get(url)
    time.sleep(3)
    return {'url':url, 'content':response.text}
 
 
def parse(res):
    res = res.result()
    print('%s parse res is %s' % (res['url'], len(res['content'])))
 
if __name__ == '__main__':
    urls = {
        'https://www.processon.com/',
    }
    pool = ThreadPoolExecutor(2)
    for i in urls:
        pool.submit(get,i).add_done_callback(parse)

39-协程介绍
单线程下实现并发的效果,指定单线程下的对CPU不断的进行切换计算,就可以实现并发的效果
协程的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行,以此来提升效率

40-协程实现与总结
协程就是单线程下实现并发,自己在代码级别实现控制
总结协程特点:
  1. 必须在只有一个单线程里实现并发
  2. 修改共享数据不需加锁
  3. 用户程序里自己保存多个控制流的上下文栈
  4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

41-greenlet模块
greenlet封装程度高,可以实现多个程序之间来回切换,无法实现检测I/O后才切换程序
from greenlet import greenlet
 
 
def eat(name):
    print('%s eat 1' % name)
    g2.switch('panda')
    print('%s eat 2' % name)
    g2.switch()
 
def play(name):
    print('%s play 1' % name)
    g1.switch()
    print('%s play 2' % name)
 
g1 = greenlet(eat)
g2 = greenlet(play)
# 切换
g1.switch('panda')
 

42-gevent模块
本质上就是封装了gevent模块,能够实现检测I/O,检测到I/O就会实现切换的操作
import gevent
import time
from gevent import monkey
# 打补丁,所有的设计IO操作的部分都全部打上补丁,做上标记
monkey.patch_all()
 
def eat(name):
    print('%s eat 1' % name)
    time.sleep(3)
    print('%s eat 2' % name)
 
 
def play(name):
    print('%s play 1' % name)
    time.sleep(5)
    print('%s play 2' % name)
 
g1 = gevent.spawn(eat, 'panda')
g2 = gevent.spawn(play, 'boy')
g1.join()
g2.join()
 

43-gevent异步提交任务
使用gevent模块就需要打补丁,一定要记得from gevent import monkey;monkey.patch_all()
import gevent
import time
from gevent import monkey;monkey.patch_all()
# 打补丁,所有的设计IO操作的部分都全部打上补丁,做上标记
 
 
def eat(name):
print('%s eat 1' % name)
time.sleep(3)
print('%s eat 2' % name)
 
 
def play(name):
print('%s play 1' % name)
time.sleep(5)
print('%s play 2' % name)
 
g1 = gevent.spawn(eat, 'panda')
g2 = gevent.spawn(play, 'boy')
gevent.joinall([g1,g2])

44-基于gevent模块实现并发的套接字通信
gevent模块是单线程下实现多个IO密集型操作的模块操作方式
服务端
import socket
from gevent import monkey,spawn;monkey.patch_all()
def comm(conn):
while True:
try:
data = conn.recv(1024)
if not data:break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
 
 
def server(ip,port):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((ip, port))
server.listen(5)
while True:
conn, addr = server.accept()
spawn(comm, conn)
server.close()
 
if __name__ == '__main__':
g = spawn(server('127.0.0.1', 8080))
g.join()
客户端
import socket
from threading import Thread,currentThread
def client():
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8080))
while True:
client.send(('%s hello'%currentThread().getName()).encode('gbk'))
data = client.recv(1024)
print(data.decode('gbk'))
client.close()
if __name__ == '__main__':
for i in range(500):
t = Thread(target=client)
t.start()
 

45-IO模型介绍
为什么要介绍IO模型?
协程是单线程下的并发,一个线程就能支持500个以上的并发量
同步调用
提交任务的方式:提交完任务以后,在等待结果,拿到结果以后执行下面的代码
异步调用
提交任务的方式:提交完任务以后,不等待结果,接着就是执行下面的代码,异步通常是要和回调函数一起执行的,
因为异步是不等待函数的结果的,但是始终需要结果,自动触发回调函数
注意:同步不等于阻塞
阻塞:遇到IO以后,如果自己不做处理,操作系统就会重新调用CPU,操作系统解决的就是IO阻塞问题
非阻塞:指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程
blocking IO 阻塞IO
nonblocking IO 非阻塞IO
IO multiplexing IO多路复用
signal driven IO 信号驱动IO
asynchronous IO 异步IO
遇到IO就会阻塞,遇到网络IO回原地阻塞
1.服务端什么样的操作属于IO?
服务端的套接字,accept()就属于阻塞,等待链接;recv()、send()也是IO行为
2.为什么这个IO行为会让用户感觉在等待?
recv经历了两个阶段:1.等待数据的阶段;2.把数据冲操作系统的缓存拷贝数据到应用程序阶段
send经历一个阶段:1.从应用程序拷贝数据到操作系统(数据量大的也会产生阻塞)

46-阻塞IO模型
当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来
阻塞IO导致程序不能实现并发的效果
线程池可以保证机器在健康的状态下稳定的运行

47-非阻塞IO模型
数据一旦已经到达本地的缓冲区以后,一定要把本地的缓冲区的数据拷贝给操作系统
非租塞IO的作用就是在等待数据的阶段让应用程序不再等待,而是继续执行后面的代码,一段时间后过来再接收数据
这样的操作叫做轮询
1.非阻塞IO在做其他事的时候会有数据来,但是不能及时响应,导致数据不能及时响应
2.服务端没有任务阻塞,就是一个死循环,对于机器来说压力太大了,这一个线程一直处于就绪状态,CPU给服务端的资源太多了,是无用的轮询方式,导致CPU无用的占用太多

48-多路复用IO模型
多路复用IO模型->IO多路复用->IO事件驱动模型
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,
当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用\(select和recvfrom\),
而blocking IO只调用了一个系统调用\(recvfrom\)。但是,用select的优势在于它可以同时处理多个connection。
阻塞阶段经历了2个阶段就拿到数据,IO多路复用经历了3个阶段,多了中间的select阶段
select的性能高是因为可以同时监控多个IO阻塞,如果select检测的IO就一个的话,性能是不如单个的纯IO阻塞的
要基于select实现套接字的并发,肯定是用来实现多个IO阻塞的操作
 
select监听fd变化的过程分析:
用户进程创建socket对象,拷贝监听的fd到内核空间,每一个fd会对应一张系统文件表,内核空间的fd响应到数据后,
就会发送信号给用户进程数据已到;
用户进程再发送系统调用,比如(accept)将内核空间的数据copy到用户空间,同时作为接受数据端内核空间的数据清除,
这样重新监听时fd再有新的数据又可以响应到了(发送端因为基于TCP协议所以需要收到应答后才会清除)。
 
该模型的优点:
相比其他模型,使用select() 的事件驱动模型只用单线程(进程)执行,占用资源少,不消耗太多 CPU,同时能够为多客户端提供服务。
如果试图建立一个简单的事件驱动的服务器程序,这个模型有一定的参考价值。
 
该模型的缺点:
首先select()接口并不是实现“事件驱动”的最好选择。因为当需要探测的句柄值较大时,select()接口本身需要消耗大量时间去轮询各个句柄。
很多操作系统提供了更为高效的接口,如linux提供了epoll,BSD提供了kqueue,Solaris提供了/dev/poll,…。
如果需要实现更高效的服务器程序,类似epoll这样的接口更被推荐。遗憾的是不同的操作系统特供的epoll接口有很大差异,
所以使用类似于epoll的接口实现具有较好跨平台能力的服务器会比较困难。
其次,该模型将事件探测和事件响应夹杂在一起,一旦事件响应的执行体庞大,则对整个模型是灾难性的。

49-异步IO模型
用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

路飞学城Python-Day32的更多相关文章

  1. 路飞学城—Python爬虫实战密训班 第三章

    路飞学城—Python爬虫实战密训班 第三章 一.scrapy-redis插件实现简单分布式爬虫 scrapy-redis插件用于将scrapy和redis结合实现简单分布式爬虫: - 定义调度器 - ...

  2. 路飞学城—Python爬虫实战密训班 第二章

    路飞学城—Python爬虫实战密训班 第二章 一.Selenium基础 Selenium是一个第三方模块,可以完全模拟用户在浏览器上操作(相当于在浏览器上点点点). 1.安装 - pip instal ...

  3. 路飞学城Python爬虫课第一章笔记

    前言 原创文章,转载引用务必注明链接.水平有限,如有疏漏,欢迎指正. 之前看阮一峰的博客文章,介绍到路飞学城爬虫课程限免,看了眼内容还不错,就兴冲冲报了名,99块钱满足以下条件会返还并送书送视频. 缴 ...

  4. 路飞学城-Python开发集训-第3章

    学习心得: 通过这一章的作业,使我对正则表达式的使用直接提升了一个level,虽然作业完成的不怎么样,重复代码有点多,但是收获还是非常大的,有点找到写代码的感觉了,遗憾的是,这次作业交过,这次集训就结 ...

  5. 路飞学城-Python开发集训-第1章

    学习体会: 在参加这次集训之前我自己学过一段时间的Python,看过老男孩的免费视频,自我感觉还行,老师写的代码基本上都能看懂,但是实际呢?....今天是集训第一次交作业的时间,突然发现看似简单升级需 ...

  6. 路飞学城-Python开发集训-第4章

    学习心得: 学习笔记: 在python中一个py文件就是一个模块 模块好处: 1.提高可维护性 2.可重用 3.避免函数名和变量名冲突 模块分为三种: 1.内置标准模块(标准库),查看所有自带和第三方 ...

  7. 路飞学城-Python开发集训-第2章

    学习心得: 这章对编码的讲解超级赞,现在对于编码终于有一点认知了,但还没有大彻大悟,还需要更加细心的琢磨一下Alex博客和视频,以前真的是被编码折磨死了,因为编码的问题而浪费的时间很多很多,现在终于感 ...

  8. 路飞学城-Python开发-第二章

    ''' 数据结构: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, '汽车之家' ...

  9. 路飞学城-Python开发-第三章

    # 数据结构: # goods = [ # {"name": "电脑", "price": 1999}, # {"name&quo ...

  10. 路飞学城-Python开发-第一章

    # 基础需求: # 让用户输入用户名密码 # 认证成功后显示欢迎信息 # 输错三次后退出程序 username = 'pandaboy' password = ' def Login(username ...

随机推荐

  1. [poj 3318] Matrix Multiplication (随机化+矩阵)

    Description You are given three n × n matrices A, B and C. Does the equation A × B = C hold true? In ...

  2. 小程序中 wx.navigateTo 页面跳转没有反应?

    页面js文件中加入 show: function () {wx.navigateTo({url: ‘/pages/show/show’})} 这个函数 目的在于要做跳转到新的页面,但是你可能会遇到一个 ...

  3. Java基础学习总结(62)——Java中的流和Socket

    按行读入方式: BufferedReader(); 1.以行为读取单位,读取比较方便. 按行读一般都是字符读. BufferedReader和PrintWriter的内存分析图: 数据流: 输入 输出 ...

  4. 关于java发送email

    转载:https://blog.csdn.net/qq_32371887/article/details/72821291 1:使用JavaMail发送邮件 // 1.创建一个程序与邮件服务器会话对象 ...

  5. CF802G Fake News (easy)

    CF802G Fake News (easy) 题意翻译 给定一个字符串询问能否听过删除一些字母使其变为“heidi” 如果可以输出“YES”,不然为“NO” 题目描述 As it's the fir ...

  6. CF899A Splitting in Teams

    CF899A Splitting in Teams 题意翻译 n个数,只有1,2,把它们任意分组,和为3的组最多多少 题目描述 There were nn groups of students whi ...

  7. Oracle解除表锁定问题

    1.肯定是你同时打开了多个操作页面,要记得关闭多个打开的sql窗口. 2.可以变相删除表,再重新创建一张同名的表来解除表被锁住的问题

  8. Python 对Twitter tweet的元素 (Word, Screen Name, Hash Tag)的词汇多样性分析

    CODE: #!/usr/bin/python # -*- coding: utf-8 -*- ''' Created on 2014-7-3 @author: guaguastd @name: tw ...

  9. MongoDB初探系列之四:MongoDB与Java共舞

    因为版本号不同,可能API也有所不同.本次学习用的是3.0版本号. 1.使用的mongodb的jdbc驱动版本号为:mongo-java-driver-3.0.0.jar 2.本节仅仅是简介JDBC操 ...

  10. Fragment状态保存

    这篇博文是对官方API Demo的FragmentRetainInstanceSupport.java的学习.路径在android-sdk-macosx/extras/android/support/ ...