Ответ 1
Twisted framework - это просто билет для этого. Но если вы не хотите этого делать, вы также можете использовать pycurl, wrapper для libcurl, который имеет свой собственный цикл событий async и поддерживает обратные вызовы.
Мне нужно использовать функцию обратного вызова в Python, где я отправляю запрос в webservice несколько раз с изменением параметра каждый раз. Я хочу, чтобы эти запросы выполнялись одновременно, а не последовательно, поэтому я хочу, чтобы функция вызывалась асинхронно.
Похоже, что asyncore - это то, что я могу использовать, но примеры, которые я видел о том, как все это работает, выглядят как overkill, поэтому мне интересно, есть ли еще один путь, по которому я должен идти. Любые предложения по модулям/процессу? В идеале я бы хотел использовать их в процедурной форме вместо создания классов, но я, возможно, не смогу обойти это.
Twisted framework - это просто билет для этого. Но если вы не хотите этого делать, вы также можете использовать pycurl, wrapper для libcurl, который имеет свой собственный цикл событий async и поддерживает обратные вызовы.
Знаете ли вы о eventlet? Он позволяет писать то, что представляется синхронным кодом, но работать он асинхронно по сети.
Вот пример супермаксимального искателя:
urls = ["http://www.google.com/intl/en_ALL/images/logo.gif",
"https://wiki.secondlife.com/w/images/secondlife.jpg",
"http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"]
import eventlet
from eventlet.green import urllib2
def fetch(url):
return urllib2.urlopen(url).read()
pool = eventlet.GreenPool()
for body in pool.imap(fetch, urls):
print "got body", len(body)
Начиная с Python 3.2, вы можете использовать concurrent.futures
для запуска параллельных задач.
Посмотрите пример ThreadPoolExecutor
:
http://docs.python.org/dev/library/concurrent.futures.html#threadpoolexecutor-example
Он генерирует потоки для извлечения HTML и действует по ответам по мере их получения.
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the url and contents
def load_url(url, timeout):
conn = urllib.request.urlopen(url, timeout=timeout)
return conn.readall()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
В приведенном выше примере используется потоковая обработка. Существует также аналогичный ProcessPoolExecutor
, который использует пул процессов, а не потоки:
http://docs.python.org/dev/library/concurrent.futures.html#processpoolexecutor-example
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the url and contents
def load_url(url, timeout):
conn = urllib.request.urlopen(url, timeout=timeout)
return conn.readall()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
(Хотя этот поток касается серверного Python.Поскольку этот вопрос был задан некоторое время назад, другие могут наткнуться на него, где они ищут аналогичный ответ на стороне клиента)
Для клиентского решения вы можете захотеть взглянуть на библиотеку Async.js, особенно на раздел "Control-Flow".
https://github.com/caolan/async#control-flow
Объединив "Параллель" с "Водопадом", вы можете достичь желаемого результата.
WaterFall (параллельная (TaskA, TaskB, TaskC) → PostParallelTask)
Если вы посмотрите пример в Control-Flow - "Auto", они приведут пример: https://github.com/caolan/async#autotasks-callback где "файл записи" зависит от "get_data" и "make_folder" и "email_link" зависит от файла записи ".
Обратите внимание, что все это происходит на стороне клиента (если вы не делаете Node.JS - на стороне сервера)
Для серверного Python посмотрите на PyCURL @https://github.com/pycurl/pycurl/blob/master/examples/basicfirst.py
Объединив приведенный ниже пример с pyCurl, вы можете добиться неблокирующей многопоточной функции.
Надеюсь, это поможет. Удачи.
Venkatt @http://MyThinkpond.com