Ответ 1
Используйте клиент async http, который использует asynchat и asyncore. http://sourceforge.net/projects/asynchttp/files/asynchttp-production/asynchttp.py-1.0/asynchttp.py/download
У меня есть сервер web.py, который отвечает на различные пользовательские запросы. Одна из этих запросов включает загрузку и анализ серии веб-страниц.
Есть ли простой способ настроить механизм загрузки URL-адресов на основе async/callback в web.py? Низкое использование ресурсов особенно важно, поскольку каждый инициированный пользователем запрос может привести к загрузке нескольких страниц.
Поток будет выглядеть так:
Пользовательский запрос → web.py → Загрузка 10 страниц параллельно или асинхронно → Анализ содержимого, возврат результатов
Я понимаю, что Twisted будет хорошим способом сделать это, но я уже в web.py, поэтому меня особенно интересует то, что может поместиться в web.py.
Используйте клиент async http, который использует asynchat и asyncore. http://sourceforge.net/projects/asynchttp/files/asynchttp-production/asynchttp.py-1.0/asynchttp.py/download
Вот интересный фрагмент кода. Я не использовал его сам, но он выглядит хорошо;)
https://github.com/facebook/tornado/blob/master/tornado/httpclient.py
Низкий уровень AsyncHTTPClient:
"Неблокирующий HTTP-клиент, поддерживаемый pycurl. Пример использования:"
import ioloop
def handle_request(response):
if response.error:
print "Error:", response.error
else:
print response.body
ioloop.IOLoop.instance().stop()
http_client = httpclient.AsyncHTTPClient()
http_client.fetch("http://www.google.com/", handle_request)
ioloop.IOLoop.instance().start()
" fetch() может принимать строковый URL или экземпляр HTTPRequest, который предлагает больше параметров, например, выполнение запросов POST/PUT/DELETE.
Ключевой аргумент max_clients для конструктора AsyncHTTPClient определяет максимальное количество одновременных операций fetch(), которые могут выполняться параллельно на каждом IOLoop. "
Выполняется также новая реализация: https://github.com/facebook/tornado/blob/master/tornado/simple_httpclient.py "Неблокирующий HTTP-клиент без внешних зависимостей... Этот класс все еще находится в разработке и еще не рекомендуется для использования в качестве продукта".
Один из вариантов заключается в том, чтобы опубликовать работу в какой-то очереди (вы могли бы использовать что-то предпринимаемое как ActiveMQ с pyactivemq или STOMP в качестве соединителя, или вы может использовать что-то легкое, например Kestrel, которое написано в Scala и говорит тот же самый проток, что и memcache, поэтому вы можете просто использовать memcache python клиент, чтобы поговорить с ним).
После установки механизма очередей вы можете создать столько или несколько рабочих задач, которые подписаны на очередь, и выполнить фактическую загрузку, как вы хотите. Вы даже можете заставить их жить на других машинах, чтобы они не мешали скорости обслуживания вашего сайта вообще. Когда рабочие завершены, они отправляют результаты обратно в базу данных или в другую очередь, где веб-сервер может их поднять.
Если вы не хотите управлять внешними рабочими процессами, вы можете сделать рабочие потоки в одном и том же процессе python, на котором запущен веб-сервер, но тогда, очевидно, он будет иметь больший потенциал для воздействия на производительность вашей веб-страницы.
Возможно, вы сможете использовать urllib
для загрузки файлов и Queue
для управления несколькими рабочими потоками. например:
import urllib
from threading import Thread
from Queue import Queue
NUM_WORKERS = 20
class Dnld:
def __init__(self):
self.Q = Queue()
for i in xrange(NUM_WORKERS):
t = Thread(target=self.worker)
t.setDaemon(True)
t.start()
def worker(self):
while 1:
url, Q = self.Q.get()
try:
f = urllib.urlopen(url)
Q.put(('ok', url, f.read()))
f.close()
except Exception, e:
Q.put(('error', url, e))
try: f.close() # clean up
except: pass
def download_urls(self, L):
Q = Queue() # Create a second queue so the worker
# threads can send the data back again
for url in L:
# Add the URLs in `L` to be downloaded asynchronously
self.Q.put((url, Q))
rtn = []
for i in xrange(len(L)):
# Get the data as it arrives, raising
# any exceptions if they occur
status, url, data = Q.get()
if status == 'ok':
rtn.append((url, data))
else:
raise data
return rtn
inst = Dnld()
for url, data in inst.download_urls(['http://www.google.com']*2):
print url, data
Я бы просто создал сервис в twisted, который сделал эту параллельную выборку и анализ и доступ к ней из web.py как простой HTTP-запрос.
В настоящее время есть отличные библиотеки Python, которые вы можете использовать - urllib3 (использует пулы потоков) и requests (использует пулы потоков через urllib3 или не блокирует IO через gevent)
Я не уверен, что понимаю ваш вопрос, поэтому я дам несколько частичных ответов, чтобы начать с.
Я не знаю, будет ли это работать, но похоже, что это может быть: EvServer: Python Asynchronous WSGI Server имеет web.py interface и может сделать push-стиль кометы клиенту браузера.
Если это не так, возможно, вы можете использовать Concurrence HTTP client для асинхронной загрузки страниц и выяснить, как обслуживать их в браузер через ajax или комету.
В соответствии с ответами MarkusQ MochiKit является хорошей библиотекой JavaScript с надежными асинхронными методами, вдохновленными Twisted.
На самом деле вы можете интегрировать скрученные с web.py. Я не совсем уверен, как, как я только делал это с django (используется с ним скрученный).