1. socket 发送请求

b'GET /s?wd=alex HTTP/1.0\r\nhost:www.baidu.com\r\n\r\n

这就是固定格式,b字节,get 后必须跟空格然后/ s?wd=alex是百度固定的后缀 后面再来空格 HTTP/1.0\r\n 这也是固定格式 后面再带个host:www.baidu.com同固定格式\r\n\r\n两个结尾

2.解除阻塞

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'))

3 io多路复用,检测多个socket是否已经发生变化(是否已经连接成功,是否可以获得数据)可读/可写

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) #select检测里面的数据有没有变化,如果有人给他发数据,就会检测到变化   他会接收3个元组   但凡rlist有值就是数据返回回来了,但凡wlist返回回来就是连接成功
    # 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

 

 4.twisted,基于事件循环实现的异步非阻塞框架   非阻塞:不等待

异步:执行完某个任务后自用调用我给他的函数。  自动下载完回调自己的函数,谁都不等待谁

1.socket 默认是阻塞的 阻塞在连接时,和接收时

2. setblocking(False)   把他变成非阻塞的

 3。io多路复用作用为,检测多个socket是否发生了变化   实际是操作系统检测socket是否发生变化,有三种模式

select:限制为1024个socket;内部检测是用的循环

poll:不限个数  但还是内部循环(水平触发)

epoll:不限个数,会调方式(边缘触发)

 python中的模块:

  select.select

  select.epoll   win没有

4。提高并发的方案

  多进程

  多线程

  单线程异步非阻塞模块(twisted)scrapy框架(单线程完成并发)

5.异步非阻塞

  非阻塞,不等待,比如创建socket对某个地址进行connect,获取接收数据recv时默认都会等待连接成功,或接收到数据,才执行后续操作,如果设置成setblocking(False)以上两个过程都不再等待但是回报blockingIOError的错,只要捕获即可,

  异步,执行完成之后自动执行回调函数或自动执行某些操作(通知)。

    比如做爬虫中向某个地址xxx发送请求,当请求执行完成之后自动执行回调函数。

6.同步阻塞

  阻塞:等

  同步:按照顺序逐步执行

io多路复用,和 

 7.在别人不改变的时候,你还想请求完成,只能自己改变

协程

  进程,操作系统中存在;

  线程,操作系统中存在;

  协程,是由程序员创造出来的一个不是真实存在的东西;

  协程,是微线程。对一个线程进行分片,使得线程在代码块之间进行来回切换执行,而不是在原来逐行执行,单纯协程没用,甚至性能降低 

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()             微协程写完了

 协程+遇到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)


gevent.joinall([
    gevent.spawn(get_page1, 'https://www.python.org/'), # 协程1
    gevent.spawn(get_page1, 'https://www.yahoo.com/'),  # 协程2
    gevent.spawn(get_page1, 'https://github.com/'),     # 协程3
])

 协程也可以称之为 微线程,就是开发者控制线程执行流程,控制先执行某段代码,然后再切换到另外函数执行代码。。。来回切换。

协程不一定可以提高并发,协程自己本身无法提高啊并发,(甚至会降低)。协程+IO切换性能提高。

进程线程区别。

进程是计算机资源分配的最小单元,主要做数据隔离,线程是工作的最小单元,主要工作的就是线程,一个进程里可以有多个线程,一个应用程序里可以有多个进程,应用场景在其他语言里基本没有进程概念,都是用的线程,在python里io操作多的时候,用线程,计算密集型的时候,用进程,因为py有GIL锁,锁住了一个进程中同一时刻只能调用一个线程,无法把cpu完全使用,多线程io不占cpu,程序员为了优化代码,创造了协程,本身不存在,协程本身让人为控制,先执行这个后执行那个,本来没用配合io就有用了,遇到io就执行别的,遇到i o切换到别的地方执行了,把线程分片了,就是让线程一直不停,一直工作,遇到io就切换到别的地方工作,io操作回来的之后再切回来,这点区别吧,py用协程的时候,要用到 greenlet 模块,实现io加协程自动切换的模块gevent

 4.单线程提供并发:

  协程+io切换  gevent

  基于事件循环的异步非阻塞框架:twisted