Python:通过select.epoll()检索多个URL
我有一个面向事件的服务器,它已经使用了 现在应该解决一个新的要求:URL应该被获取(异步) 到目前为止,我一直使用请求库,而且我一直使用它是同步的,而不是异步的 如何将请求库(或不同的urllib)与linux e波尔结合使用 requests library文档对此有说明,但只提到异步框架(而不是select.epoll()):Python:通过select.epoll()检索多个URL,python,asynchronous,python-requests,urllib,epoll,Python,Asynchronous,Python Requests,Urllib,Epoll,我有一个面向事件的服务器,它已经使用了 现在应该解决一个新的要求:URL应该被获取(异步) 到目前为止,我一直使用请求库,而且我一直使用它是同步的,而不是异步的 如何将请求库(或不同的urllib)与linux e波尔结合使用 requests library文档对此有说明,但只提到异步框架(而不是select.epoll()): 我没有与select.epoll()结婚。到目前为止,一切都很顺利。如果可行,我可以使用不同的解决方案 背景:更大的问题是“我应该使用select.epoll()还是
我没有与select.epoll()结婚。到目前为止,一切都很顺利。如果可行,我可以使用不同的解决方案 背景:更大的问题是“我应该使用select.epoll()还是python拥有的众多异步框架之一?”。但StackOverflow的问题不能太广泛。这就是为什么这个问题集中在“通过select.epoll()检索多个URL”。如果你有更大问题的提示,请留下评论 如果您感到好奇,我在业余时间开发的一个小项目需要这个问题:(IPO是一个基于PostgreSQL的开源异步作业队列。)如何将请求库(或不同的urllib)与linux-epoll结合使用? 不幸的是,除非在构建这样一个库时考虑到了这种集成,否则您不能这样做epoll,以及select/poll/kqueue,其他是I/O多路复用系统调用,需要围绕它构建整体程序体系结构 简单地说,一个典型的程序结构可以归结为以下几点
- 你需要有一堆文件描述符(在你的例子中是非阻塞模式下的套接字)
- 系统调用(man-epoll\u wait在epoll的情况下)阻塞,直到一个或多个描述符上发生指定事件
- 返回可用于I/O的描述符的信息
如果您真的需要python 2.x,请根据所需的稳定性和假设的峰值负载使用上述方法之一,在进行高性能开发时,我们总是根据自己的情况选择武器。因此,它仍然太宽泛,无法回答 但更大的问题更简单。只有IO绑定的程序适合异步 epoll和异步的目的是什么?避免CPU等待IO而什么也不做。CPU等待IO块,IO块是因为没有数据可读取或没有空间可写入 引入缓冲区是为了减少系统调用。当您在流上调用read时,实际上是从缓冲区读取。(概念,不是很准确) Select或epoll是非阻塞繁忙轮询(epoll通过中断底层实现)
while true {
for i in stream[]{
if i has data
read until unavailable
}
}
这是愚蠢的,所以有选择和epoll。
每次从缓冲区读取数据时,都会有数据等待您,它是高速IO,然后epoll/select是您的最佳选择。当缓冲区总是空的时候,它是一个慢流,IO绑定,异步非常适合这种情况
我对异步不是很了解,对我来说是
from tornado import (httpserver, options,
ioloop, web, gen)
import time
import ujson as json
from collections import defaultdict
class Check(web.RequestHandler):
@gen.coroutine
def get(self):
try:
data = int(self.get_argument('data'))
except ValueError:
raise web.HTTPError(400, reason='Invalid value for data')
delay = 100
start = time.time()
print('Processed: {!r}'.format(data))
yield gen.Task(ioloop.IOLoop.instance().add_timeout, start + delay / 1000.)
self.write('.')
end = time.time()
self.finish()
if __name__ == '__main__':
port = 4545
application = web.Application([
(r'/get', Check)
])
http_server = httpserver.HTTPServer(application)
http_server.listen(port)
print('Listening on port: {}'.format(port))
ioloop.IOLoop.instance().start()
import grequests
from tornado.httpclient import HTTPClient
import time
def call_serial(num, httpclient):
url = 'http://127.0.0.1:4545/get?data={}'.format(num)
response = httpclient.fetch(url)
print('Added: {!r}'.format(num))
def call_async(mapper):
futures = (grequests.get(url) for url,_ in mapper)
responses = grequests.map(futures)
for response, (url,num) in zip(responses, mapper):
print('Added: {!r}'.format(num))
def check(num):
if num % 2 == 0:
return False
return True
def serial_calls(httpclient, up_to):
for num in range(up_to):
if check(num):
call_serial(num, httpclient)
def async_calls(httpclient, up_to):
mapper = []
for num in range(up_to):
if check(num):
url = 'http://127.0.0.1:4545/get?data={}'.format(num)
mapper.append((url,num))
call_async(mapper)
if __name__ == '__main__':
httpclient = HTTPClient()
print('SERIAL CALLS')
serial_calls(httpclient, 100)
print('ASYNC CALLS')
async_calls(httpclient, 100)
httpclient.close()