Ref: HOWTO Fetch Internet Resources Using The urllib Package

Ref: Python High Performance - Second Edition【基于python3】

Ref: http://online.fliphtml5.com/odjuw/kcqs/#p=8【在线电子书】

Ref: 廖雪峰的异步IO【还是这个比较好一点】

Ref: Efficient web-scraping with Python’s asynchronous programming【参考】

Ref: A Web Crawler With asyncio Coroutines【参考】

一些概念

并行:parallel

并发:concurrent

协程:Coroutines

一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。

协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。

这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

Linux异步原理

参考一:boost coroutine with multi core

参考二:poll 和 select

poll 和 select 的实现基本上是一致的,只是传递参数有所不同,他们的基本流程如下:

1. 复制用户数据到内核空间

2. 估计超时时间

3. 遍历每个文件并调用f_op->poll 取得文件当前就绪状态, 如果前面遍历的文件都没有就绪,向文件插入wait_queue节点

4. 遍历完成后检查状态:

a). 如果已经有就绪的文件转到5;

b). 如果有信号产生,重启poll或select(转到 1或3);

c). 否则挂起进程等待超时或唤醒,超时或被唤醒后再次遍历所有文件取得每个文件的就绪状态

5. 将所有文件的就绪状态复制到用户空间

6. 清理申请的资源

写在开始


requests.get 串行策略

import requests
import string
import random # 生成url
def generate_urls(base_url, num_urls):
"""
We add random characters to the end of the URL to break any caching
mechanisms in the requests library or the server
"""
for i in range(num_urls):
yield base_url + "".join(random.sample(string.ascii_lowercase, 10)) # 执行url
def run_experiment(base_url, num_iter=500):
response_size = 0
for url in generate_urls(base_url, num_iter):
print(url)
response = requests.get(url)
response_size += len(response.text)
return response_size

if __name__ == "__main__":
import time
delay = 100
num_iter = 50
base_url = "http://www.baidu.com/add?name=serial&delay={}&".format(delay) start = time.time()
result = run_experiment(base_url, num_iter)
end = time.time()
print("Result: {}, Time: {}".format(result, end - start))

Gevent 方案

【暂时放弃该方案,太复杂且代码不可用】

以下是有变化部分的代码:

from gevent import monkey
monkey.patch_socket()
#----------------------------------
import gevent
from gevent.coros import Semaphore
import urllib2
from contextlib import closing
import string
import random
def download(url, semaphore):
with semaphore, closing(urllib2.urlopen(url)) as data:
return data.read() def chunked_requests(urls, chunk_size=100):
semaphore = Semaphore(chunk_size)
requests = [gevent.spawn(download, u, semaphore) for u in urls]
for response in gevent.iwait(requests):
yield response def run_experiment(base_url, num_iter=500):
urls = generate_urls(base_url, num_iter)
response_futures = chunked_requests(urls, 100)
response_size = sum(len(r.value) for r in response_futures)
return response_size

gevent.spawn()

Create a new Greenlet object and schedule it to run function(*args, **kwargs).

greenlet的源代码,代码不多,就2000行C语言的代码,其中有一部分栈寄存器的修改的代码是由汇编实现的。

一句话来说明greenlet的实现原理:通过栈的复制切换来实现不同协程之间的切换。

contextlib 的 closing

对于不支持使用 "with"语句 的 "类似文件” 的对象,使用 contextlib.closing():

import contextlib.closing
with closing(urllib.urlopen("http://www.python.org/")) as front_page:
for line in front_page:
print line

异步IO


一、简单的模型

yield是有返回值的。

def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK' def produce(c):
c.send(None)  # <-- 启动生成器
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close() #-------------------------------------------------- c = consumer()
produce(c)    # 给消费者c喂消息

二、asyncio 的由来

传统方式

Ref: https://www.liaoxuefeng.com/wiki/1016959663602400/1017970488768640

(1) 从asyncio模块中直接获取一个EventLoop的引用,

(2) 然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

import threading
import asyncio @asyncio.coroutine
def hello():
print('Hello world! (%s)' % threading.currentThread())
yield from asyncio.sleep(1) # 看成是一个耗时的io操作
print('Hello again! (%s)' % threading.currentThread()) loop = asyncio.get_event_loop()   # (1) 获取一个EventLoop引用
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))  # (2) 将携程扔到EventLoop中去执行
loop.close()

异步wget网页

writer.drain():这是一个与底层IO输入缓冲区交互的流量控制方法。当缓冲区达到上限时,drain()阻塞,待到缓冲区回落到下限时,写操作可以被恢复。当不需要等待时,drain()会立即返回。

#%%
import asyncio @asyncio.coroutine
def wget(host):
print('wget %s...' % host) # (1) 首先,获得socket双向管道
connect = asyncio.open_connection(host, 80)
reader, writer = yield from connect # (2) 发送request要网页内容
header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
writer.write(header.encode('utf-8'))
yield from writer.drain() # (3) 获得网页内容
while True:
line = yield from reader.readline()
if line == b'\r\n':
break
print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
# Ignore the body, close the socket
writer.close()

loop = asyncio.get_event_loop()
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

总结下来就是主要做了两件事:

(1) @asyncio.coroutine

(2) yield from:不希望堵塞的地方

换为 async, await

换个写法,看上去干净一些。

import threading
import asyncio async def hello():
print('Hello world! (%s)' % threading.currentThread())
await asyncio.sleep(1) # 看成是一个耗时的io操作
print('Hello again! (%s)' % threading.currentThread()) loop = asyncio.get_event_loop()   # (1) 获取一个EventLoop引用
tasks = [hello(), hello()]
loop.run_until_complete(asyncio.wait(tasks))  # (2) 将协程扔到EventLoop中去执行
loop.close()

三、aiohttp 助力

现在是把asyncio放在了服务器端!

asyncio可以实现单线程并发IO操作。如果仅用在客户端,发挥的威力不大。如果把asyncio用在服务器端,例如Web服务器,由于HTTP连接就是IO操作,因此可以用单线程+coroutine实现多用户的高并发支持。

# server code

import asyncio
from aiohttp import web async def index(request):
await asyncio.sleep(0.5)
return web.Response(body=b'<h1>Index</h1>') async def hello(request):
await asyncio.sleep(0.5)
text = '<h1>hello, %s!</h1>' % request.match_info['name']
return web.Response(body=text.encode('utf-8')) async def init(loop):
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/hello/{name}', hello)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
print('Server started at http://127.0.0.1:8000...')
return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()

异步百万并发


Ref: python异步编程之asyncio(百万并发)

文章不错,详见链接。

值得注意的一点是:最大并发限制的设置。

semaphore = asyncio.Semaphore(500) # 限制并发量为500

 

End.

[Advanced Python] 10 - Transfer parameters的更多相关文章

  1. Python 10 —— 杂

    Python 10 —— 杂 科学计算 NumPy:数组,数组函数,傅里叶变换 SciPy:依赖于NumPy,提供更多工具,比如绘图 绘图 Matplitlib:依赖于NumPy和Tkinter

  2. python 10分钟入门pandas

    本文是对pandas官方网站上<10 Minutes to pandas>的一个简单的翻译,原文在这里.这篇文章是对pandas的一个简单的介绍,详细的介绍请参考:Cookbook .习惯 ...

  3. Python 10 训练模型

    原文:https://www.cnblogs.com/denny402/p/7520063.html 原文:https://www.jianshu.com/p/84f72791806f 原文:http ...

  4. python 10大算法之一 LinearRegression 笔记

    简单的线性回归预测房价 #!/usr/bin/env python # encoding: utf-8 """ @version: @author: --*--. @fi ...

  5. Python 10 协程,异步IO,Paramiko

    本节内容 Gevent协程 异步IO Paramiko 携程 协程,又称为微线程,纤程(coroutine).是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文 ...

  6. [ Python - 10 ] 练习:批量管理主机工具

    需求: 主机分组 登录后显示主机分组,选择分组后查看主机列表 可批量执行命令.发送文件,结果实时返回 主机用户名密码可以不同 流程图: 说明: ## 需求: 主机分组 登录后显示主机分组,选择分组后查 ...

  7. python 10 动态参数

    目录 1. 函数的动态参数 1.1 动态位置参数(*arges) 1.2 动态关键字参数 (**kwargs) 1.3 万能传参: 2. 函数的注释 3. 名称空间 4. 函数嵌套 5. 函数变量修改 ...

  8. [Advanced Python] 11 - Implement a Class

    基础概念:[Python] 08 - Classes --> Objects 进阶概念:[Advanced Python] 11 - Implement a Class 参考资源:廖雪峰,面向对 ...

  9. [Advanced Python] 16 - Google style guide for programming

    Ref: Python 风格指南 - 内容目录 这里主要记录一下值得注意的地方. Python语言规范 Lint:vsCode自带 导入:完整路径 异常 Ref: [Python] 07 - Stat ...

随机推荐

  1. Windows Server 2008磁盘管理

    下面学习一下磁盘管理,基本磁盘 分区 空间只能是同一块磁盘的空间,动态磁盘  卷 空间可以是多块硬盘上的空间,怎么创建 RAID-0  条带卷 读写快 无容错 适合存放不太重要的数据 ,RAID-1  ...

  2. 用python解析JSON

    先来认识下JSON JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使 ...

  3. 用小程序·云开发两天搭建mini论坛丨实战

    笔者最近涉猎了小程序相关的知识,于是利用周末时间开发了一款类似于同事的小程序,深度体验了小程序云开发模式提供的云函数.数据库.存储三大能力.关于云开发,可参考文档:小程序·云开发. 个人感觉云开发带来 ...

  4. 企查查app (二)

    企查查app sign算法破解 已删除!!!! 这次我们又找到设备id,现在就只差aXM这个了. 关注小白公众号,小白带你成长.

  5. Keras实例教程(1)

    https://blog.csdn.net/baimafujinji/article/details/78384792

  6. SQL优化没思路,智能优化工具来帮你

    前言 作为DBA或系统管理员,我们有时会遇到一个慢SQL需要优化,但是通过分析执行计划又没有找到好的优化思路,或者优化之后效果不明显,没有达到自己理想的预期,此时的你是不是很焦虑?此时你一定想如果有一 ...

  7. UML类图详解和示例

    ps:博客园markdown不能自动生成列表,更好的阅读体验可访问我的个人博客http://www.isspark.com/archives/UMLDescription UML类图概述 什么是UML ...

  8. Git学习笔记-相关命令记录

    内容来自:https://www.liaoxuefeng.com/wiki/896043488029600/896067074338496 1.Linux安装Git 首先,你可以试着输入git,看看系 ...

  9. 企业代码版本管理之争:TrunkBased vs GitFlow vs AoneFlow vs OneFlow vs ExeFlow

    目录 引言 TrunkBased GitFlow AoneFlow OneFlow ExeFlow 综述 引言 网络上版本管理系统之争持久而喧嚣,依照声量来讲目前应该是Git占了较大的优势.不过我们本 ...

  10. office web apps server安装

    1.准备服务器 准备一台windows server 2012 R2服务器,修改计算机名称加入域,如果是通过虚拟机复制导致sid冲突,可以先运行 c:\windows\system32\sysprep ...