0、基于socket发送Http请求

import socket
import requests # 方式一
ret = requests.get('https://www.baidu.com/s?wd=alex') # 方式二
client = socket.socket() # 百度创建连接: 阻塞
client.connect(('www.baidu.com',80)) # 问百度我要什么?
client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n') # 我等着接收百度给我的回复
chunk_list = []
while True:
chunk = client.recv(8096)
if not chunk:
break
chunk_list.append(chunk) body = b''.join(chunk_list)
print(body.decode('utf-8'))

socket发送请求

# by luffycity.com

import socket
import requests
# #################### 解决并发:单线程 ####################
# 方式一
key_list = ['alex','db','sb']
for item in key_list:
ret = requests.get('https://www.baidu.com/s?wd=%s' %item) # 方式二
def get_data(key):
# 方式二
client = socket.socket() # 百度创建连接: 阻塞
client.connect(('www.baidu.com',80)) # 问百度我要什么?
client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n') # 我等着接收百度给我的回复
chunk_list = []
while True:
chunk = client.recv(8096)
if not chunk:
break
chunk_list.append(chunk) body = b''.join(chunk_list)
print(body.decode('utf-8')) key_list = ['alex','db','sb']
for item in key_list:
get_data(item) # #################### 解决并发:多线程 ####################
import threading key_list = ['alex','db','sb']
for item in key_list:
t = threading.Thread(target=get_data,args=(item,))
t.start() # #################### 解决并发:单线程+IO不等待 ####################
# IO请求?
# 数据回来了?

socket 单线程和多线程

# by luffycity.com
import socket client = socket.socket()
client.setblocking(False) # 将原来阻塞的位置变成非阻塞(报错)
# 百度创建连接: 阻塞 try:
client.connect(('www.baidu.com',80)) # 执行了但报错了
except BlockingIOError as e:
pass # 检测到已经连接成功 # 问百度我要什么?
client.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n') # 我等着接收百度给我的回复
chunk_list = []
while True:
chunk = client.recv(8096) # 将原来阻塞的位置变成非阻塞(报错)
if not chunk:
break
chunk_list.append(chunk) body = b''.join(chunk_list)
print(body.decode('utf-8'))

前戏

一、IO多路复用

  1、IO多路复用作用:

    检测多个socket是否已经发生变化(是否已经连接成功/是否已经获取数据)(可读/可写)

    可以监听所有的IO请求状态

client.setblocking(False) # 将原来阻塞的位置变成非阻塞(报错)
        基于事件循环实现的异步非阻塞框架:lzl
非阻塞:不等待
异步:执行完某个人物后自动调用我给他的函数。 Python中开源 基于事件循环实现的异步非阻塞框架 Twisted

  3、单线程的并发

     基于IO多路复用+socket实现并发请求(一个线程100个请求)

        IO多路复用
socket非阻塞
    import select  #利用此模块 可以检测数据是否拿到

    rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005)
# socket_list 检测服务端是否给我返回数据
# ,conn_list 检测是否连接成功
import socket
import select client1 = socket.socket()
client1.setblocking(False) # 百度创建连接: 非阻塞 try:
client1.connect(('www.baidu.com',80))
except BlockingIOError as e:
pass client2 = socket.socket()
client2.setblocking(False) # 百度创建连接: 非阻塞
try:
client2.connect(('www.sogou.com',80))
except BlockingIOError as e:
pass client3 = socket.socket()
client3.setblocking(False) # 百度创建连接: 非阻塞
try:
client3.connect(('www.oldboyedu.com',80))
except BlockingIOError as e:
pass socket_list = [client1,client2,client3]
conn_list = [client1,client2,client3] while True:
rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005)
# wlist中表示已经连接成功的socket对象
for sk in wlist:
if sk == client1:
sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')
elif sk==client2:
sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')
else:
sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')
conn_list.remove(sk)
for sk in rlist:
chunk_list = []
while True:
try:
chunk = sk.recv(8096)
if not chunk:
break
chunk_list.append(chunk)
except BlockingIOError as e:
break
body = b''.join(chunk_list)
# print(body.decode('utf-8'))
print('------------>',body)
sk.close()
socket_list.remove(sk)
if not socket_list:
break

单线程的并发

        基于事件循环实现的异步非阻塞框架:Twisted
非阻塞:不等待
异步:执行完某个人物后自动调用我给他的函数。 Python中开源 基于事件循环实现的异步非阻塞框架 Twisted
# by luffycity.com
import socket
import select class Req(object):
def __init__(self,sk,func):
self.sock = sk
self.func = func def fileno(self):
return self.sock.fileno() class Nb(object): def __init__(self):
self.conn_list = []
self.socket_list = [] def add(self,url,func):
client = socket.socket()
client.setblocking(False) # 非阻塞
try:
client.connect((url, 80))
except BlockingIOError as e:
pass
obj = Req(client,func)
self.conn_list.append(obj)
self.socket_list.append(obj) def run(self): while True:
rlist,wlist,elist = select.select(self.socket_list,self.conn_list,[],0.005)
# wlist中表示已经连接成功的req对象
for sk in wlist:
# 发生变换的req对象
sk.sock.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')
self.conn_list.remove(sk)
for sk in rlist:
chunk_list = []
while True:
try:
chunk = sk.sock.recv(8096)
if not chunk:
break
chunk_list.append(chunk)
except BlockingIOError as e:
break
body = b''.join(chunk_list)
# print(body.decode('utf-8'))
sk.func(body)
sk.sock.close()
self.socket_list.remove(sk)
if not self.socket_list:
break def baidu_repsonse(body):
print('百度下载结果:',body) def sogou_repsonse(body):
print('搜狗下载结果:', body) def oldboyedu_repsonse(body):
print('老男孩下载结果:', body) t1 = Nb()
t1.add('www.baidu.com',baidu_repsonse)
t1.add('www.sogou.com',sogou_repsonse)
t1.add('www.oldboyedu.com',oldboyedu_repsonse)
t1.run() #
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
# client1 = socket.socket()
# client1.setblocking(False) # 百度创建连接: 非阻塞
#
# try:
# client1.connect(('www.baidu.com',80))
# except BlockingIOError as e:
# pass
#
#
# client2 = socket.socket()
# client2.setblocking(False) # 百度创建连接: 非阻塞
# try:
# client2.connect(('www.sogou.com',80))
# except BlockingIOError as e:
# pass
#
#
# client3 = socket.socket()
# client3.setblocking(False) # 百度创建连接: 非阻塞
# try:
# client3.connect(('www.oldboyedu.com',80))
# except BlockingIOError as e:
# pass
#
# class Foo(object):
# def __init__(self,sk):
# self.sk = sk
#
# def fileno(self):
# return self.sk.fileno()
#
# """
# 1. select.select(socket_list,conn_list,[],0.005)
# select监听的 socket_list/conn_list 内部会调用列表中每一个值的fileno方法,获取该返回值并去系统中检测。
#
# 2. 方式一:
# select.select([client1,client2,client3],[client1,client2,client3],[],0.005)
# 3. 方式二:
# select.select([Foo(client1),Foo(client2),(client3)],Foo(client1),Foo(client2),(client3),[],0.005)
# """
# socket_list = [Foo(client1),client2,client3] # client1.fileno
# conn_list = [client1,client2,client3]
#
# while True:
# rlist,wlist,elist = select.select(socket_list,conn_list,[],0.005)
# # wlist中表示已经连接成功的socket对象
# for sk in wlist:
# if sk == client1:
# sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n')
# elif sk==client2:
# sk.sendall(b'GET /web?query=fdf HTTP/1.0\r\nhost:www.sogou.com\r\n\r\n')
# else:
# sk.sendall(b'GET /s?wd=alex HTTP/1.0\r\nhost:www.oldboyedu.com\r\n\r\n')
# conn_list.remove(sk)
# for sk in rlist:
# chunk_list = []
# while True:
# try:
# chunk = sk.recv(8096)
# if not chunk:
# break
# chunk_list.append(chunk)
# except BlockingIOError as e:
# break
# body = b''.join(chunk_list)
# # print(body.decode('utf-8'))
# print('------------>',body)
# sk.close()
# socket_list.remove(sk)
# if not socket_list:
# break

单线程的并发高级版

总结:
1. socket默认是否是阻塞的?阻塞体现在哪里?
    是阻塞的, 链接的时候 accept recv 2. 如何让socket编程非阻塞?
    .setblocking(Flase) 3. IO多路复用作用?
检测多个socket是否发生变化。
操作系统检测socket是否发生变化,有三种模式:
select:最多1024个socket;循环去检测。
poll:不限制监听socket个数;循环去检测(水平触发)。
epoll:不限制监听socket个数;回调方式(边缘触发)。
Python模块:
select.select
select.epoll 4. 提高并发方案:
- 多进程
- 多线程
- 异步非阻塞模块(Twisted) scrapy框架(单线程完成并发) 5. 什么是异步非阻塞?
- 非阻塞,不等待。
比如创建socket对某个地址进行connect、获取接收数据recv时默认都会等待(连接成功或接收到数据),才执行后续操作。
如果设置setblocking(False),以上两个过程就不再等待,但是会报BlockingIOError的错误,只要捕获即可。
- 异步,通知,执行完成之后自动执行回调函数或自动执行某些操作(通知)。
比如做爬虫中向某个地址baidu.com发送请求,当请求执行完成之后自执行回调函数。 6. 什么是同步阻塞?
- 阻塞:等
- 同步:按照顺序逐步执行 key_list = ['alex','db','sb']
for item in key_list:
ret = requests.get('https://www.baidu.com/s?wd=%s' %item)
print(ret.text) 7. 概念
之前:
            # 你写的代码:7000w
v = [
[11,22], # 每个都有一个append方法
[22,33], # 每个都有一个append方法
[33,44], # 每个都有一个append方法
] # 王思聪
for item in v:
print(item.append)
        之后:
            class Foo(object):
def __init__(self,data,girl):
self.row = data
self.girl = girl def append(self,item):
self.row.append(item) v = [
Foo([11,22],'雪梨'), # 每个都有一个append方法
Foo([22,33],'冰糖'), # 每个都有一个append方法
Foo([33,44],'糖宝'), # 每个都有一个append方法
] for item in v:
print(item.append)
item.girl

二、协程

概念:
进程,操作系统中存在;
线程,操作系统中存在;
协程,是由程序员创造出来的一个不是真实存在的东西; 协程:是微线程,对一个线程进程分片,使得线程在代码块之间进行来回切换执行,而不是在原来逐行执行。
import greenlet

def f1():
print(11)
gr2.switch()
print(22)
gr2.switch() def f2():
print(33)
gr1.switch()
print(44) # 协程 gr1
gr1 = greenlet.greenlet(f1)
# 协程 gr2
gr2 = greenlet.greenlet(f2) gr1.switch() 注意:单纯的协程无用 def f1():
print(11)
print(33) def f2():
print(22)
print(44) f1()
f2()

单独协程

协程 + 遇到IO就切换 => 牛逼起来了

from gevent import monkey
monkey.patch_all() # 以后代码中遇到IO都会自动执行greenlet的switch进行切换
import requests
import gevent def get_page1(url):
ret = requests.get(url)
print(url,ret.content) def get_page2(url):
ret = requests.get(url)
print(url,ret.content) def get_page3(url):
ret = requests.get(url)
print(url,ret.content) gevent.joinall([
gevent.spawn(get_page1, 'https://www.python.org/'), # 协程1
gevent.spawn(get_page2, 'https://www.yahoo.com/'), # 协程2
gevent.spawn(get_page3, 'https://github.com/'), # 协程3
])
总结:
1. 什么是协程?
协程也可以称为“微线程”,就是开发者控制线程执行流程,控制先执行某段代码然后再切换到另外函执行代码...来回切换。 2. 协程可以提高并发吗?
协程自己本身无法实现并发(甚至性能会降低)。
协程+IO切换性能提高。 3. 进程、线程、协程的区别? 4. 单线程提供并发:
- 协程+IO切换:gevent
- 基于事件循环的异步非阻塞框架:Twisted
- 手动实现协程:yield关键字生成器
def f1():
print(11)
yield
print(22)
yield
print(33) def f2():
print(55)
yield
print(66)
yield
print(77) v1 = f1()
v2 = f2() next(v1) # v1.send(None)
next(v2) # v1.send(None)
next(v1) # v1.send(None)
next(v2) # v1.send(None)
next(v1) # v1.send(None)
next(v2) # v1.send(None)

手动实现协程:yield关键字生成器


总结

重点总结:
1. 进程、线程、协程的区别? ********** 2. 写代码:gevent *****
from gevent import monkey
monkey.patch_all() # 以后代码中遇到IO都会自动执行greenlet的switch进行切换
import requests
import gevent def get_page1(url):
ret = requests.get(url)
print(url,ret.content) def get_page2(url):
ret = requests.get(url)
print(url,ret.content) def get_page3(url):
ret = requests.get(url)
print(url,ret.content) gevent.joinall([
gevent.spawn(get_page1, 'https://www.python.org/'), # 协程1
gevent.spawn(get_page2, 'https://www.yahoo.com/'), # 协程2
gevent.spawn(get_page3, 'https://github.com/'), # 协程3
]) 3. 写代码:twisted *****
from twisted.web.client import getPage, defer
from twisted.internet import reactor def all_done(arg):
reactor.stop() def callback(contents):
print(contents) deferred_list = []
url_list = ['http://www.bing.com', 'http://www.baidu.com', ]
for url in url_list:
deferred = getPage(bytes(url, encoding='utf8'))
deferred.addCallback(callback)
deferred_list.append(deferred) dlist = defer.DeferredList(deferred_list)
dlist.addBoth(all_done) reactor.run() 4. 异步非阻塞 5. IO多路复用
作用:可以监听所有的IO请求的状态。
- socket I,input
o,output
三种模式:
- select
- poll
- epoll

两周总结:
网络编程:
1. 网络基础
- 网卡
- IP
- ...
2. OSI 7层
3. 三次握手四次挥手
4. BS和CS架构?
5. socket基本代码
6. 黏包
7. 断点续传
8. 协议
自定义协议:{'code':10001,data:{...}}
Http协议:GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n 9. 面向对象+高级作业:反射/面向对象 并发编程:
1. 进程、线程、协程的区别? 2. 线程
- 基本写法
- 实例化
- 继承
- 锁
- RLock
...
- 线程池
3. 进程
- 基本写法
- 实例化
- 继承
- 锁
- RLock
...
- 线程池
- 进程数据共享 4. 协程
- 协程
- 协程+IO:gevent 5. IO多路复用 6. 异步/同步 阻塞/非阻塞

两周总结

day 35 协程 IO多路复用的更多相关文章

  1. 协程IO多路复用

    协程:单线程下实现并发并发:伪并行,遇到IO就切换,单核下多个任务之间切换执行,给你的效果就是貌似你的几个程序在同时执行.提高效率任务切换 + 保存状态并行:多核cpu,真正的同时执行串行:一个任务执 ...

  2. 协程 IO多路复用

    -----------------------------------------------------------------试试并非受罪,问问并不吃亏.善于发问的人,知识丰富. # # ---- ...

  3. Python之路--协程/IO多路复用

    引子: 之前学习过了,线程,进程的概念,知道了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来说我们已经算是把CPU的利用率提高很多了.但是我们知道无论是创建多进程还是创建多 ...

  4. 12_进程,线程,协程,IO多路复用的区别

    1.进程 1.进程可以使用计算机多核 2.进程是资源分配的单位 3.进程的创建要比线程消耗更多的资源效率很低 4.进程空间独立,数据安全性跟好操作有专门的进程间通信方式 5.一个进程可以包含多个线程, ...

  5. Day 42 协程. IO 并发

    一.什么是协程? 是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 协程相比于线程切换效率更快了. ...

  6. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

  7. 05网络并发 ( GIL+进程池与线程池+协程+IO模型 )

    目录 05 网络并发 05 网络并发

  8. 协程 & IO模型 & HTTP协议

    今日内容 进程池与线程池的基本使用 协程理论与实操 IO模型 前端简介 内容详细 一.进程池与线程池的基本使用 1.进程池与线程池的作用 为了保证计算机硬件安全的前提下,提升程序的运行效率 2.回调机 ...

  9. day 35 协程与gil概念

    博客链接: http://www.cnblogs.com/linhaifeng/articles/7429894.html 今日概要: 1 生产者消费者模型(补充) 2 GIL(进程与线程的应用场景) ...

随机推荐

  1. unity image 设置图片

    从任意文件目录下读取文件并在unity中显示: 1)读取目标文件 byte[] imageByte = File.ReadAllBytes(imagePath); 2)转换成纹理 texture.Lo ...

  2. unity text实现鼠标光标

    由于项目需求,需要在text上实现鼠标的cursor,并且随着点击位置cursor移动.实现方法: 1)新建一个光标的prefab(简单为之,直接在image中添加一个竖线spirte),增加脚本控制 ...

  3. Vue躬行记(5)——组件通信

    组件之间除了保持独立之外,还需要相互通信,本章将介绍几种通信的方式. 一.直接访问 Vue提供了三个实例属性,可直接访问父组件.子组件和根实例,如下所列. (1)$parent:父组件. (2)$ro ...

  4. git从远程仓库拉取内容或向远程仓库上传内容

    一.将本地文件上传到远程仓库步骤 git init git add . git commit -m "初始框架" git remote add origin https://git ...

  5. Splash API 调用

    render.html render.html 接口用于获取 JavaScript 渲染的页面的 HTML 代码,接口地址就是 Splash 的运行地址加此接口名称,例如http://localhos ...

  6. python全局变量及局部变量

    变量作用域 全局变量(global):在函数外部定义,在整个全局范围都有效 局部变量(local) 在函数内部定义,局部变量在局部范围内使用 数字,字符串,元组,修改其变量值时需要加globle,列表 ...

  7. Oracle“ORA-00911: 无效字符”解决方式

    在工作中碰到ORA-00911:无效字符的问题, 代码如下: <select id="querySendMsg" parameterType="map" ...

  8. python之装饰器的概念

    装饰器对于程序来说虽然不是必要的,但有时候却可以提高效率,也可以保证程序的安全. 说装饰器之前需要掌握闭包,前面一篇文章已经介绍过,这里不再重复. 那么,装饰器到底是什么东西呢?看下面这个例子 首先定 ...

  9. NOIP的模板--考前复习

    距离NOIP还有25天 可以去放弃一些巨难得题目去搞一些模板了 -------在校老师的原话 一·快排 虽然可以手打,最好用STL,里面有很多优化,会快很多 #include<iostream& ...

  10. python机器学习——随机梯度下降

    上一篇我们实现了使用梯度下降法的自适应线性神经元,这个方法会使用所有的训练样本来对权重向量进行更新,也可以称之为批量梯度下降(batch gradient descent).假设现在我们数据集中拥有大 ...