Раздражающая проблема Twisted Python - PullRequest
2 голосов
/ 14 апреля 2010

Я пытаюсь ответить на следующий вопрос из личного интереса: Какой самый быстрый способ отправить 100 000 HTTP-запросов в Python?

И это то, что я дошел до этого, но я испытываю нечто очень странное.

Когда installSignalHandlers равно True , оно просто зависает. Я вижу, что DelayedCall экземпляры находятся в reactor._newTimedCalls, но processResponse никогда не вызывается.

Когда installSignalHandlers равен False , выдает ошибку и работает.

from twisted.internet import reactor
from twisted.web.client import Agent
from threading import Semaphore, Thread
import time

concurrent = 100
s = Semaphore(concurrent)
reactor.suggestThreadPoolSize(concurrent)
t=Thread(
    target=reactor.run,
    kwargs={'installSignalHandlers':True})
t.daemon=True
t.start()


agent = Agent(reactor)


def processResponse(response,url):
    print response.code, url
    s.release()

def processError(response,url):
    print "error", url
    s.release()

def addTask(url):
    req = agent.request('HEAD', url)
    req.addCallback(processResponse, url)
    req.addErrback(processError, url)


for url in open('urllist.txt'):
    addTask(url.strip())    
    s.acquire()
while s._Semaphore__value!=concurrent:
    time.sleep(0.1)     

reactor.stop()

А вот ошибка, которую выдает, когда installSignalHandlers имеет значение True: (Примечание: это ожидаемое поведение! Вопрос в том, почему он не работает, когда installSignalHandlers имеет значение False.)

Traceback (most recent call last):
  File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 396, in fireEvent
    DeferredList(beforeResults).addCallback(self._continueFiring)
  File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 224, in addCallback
    callbackKeywords=kw)
  File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 213, in addCallbacks
    self._runCallbacks()
  File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 371, in _runCallbacks
    self.result = callback(self.result, *args, **kw)
--- <exception caught here> ---
  File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 409, in _continueFiring
    callable(*args, **kwargs)
  File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 1165, in _reallyStartRunning
    self._handleSignals()
  File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 1105, in _handleSignals
    signal.signal(signal.SIGINT, self.sigInt)
exceptions.ValueError: signal only works in main thread

Что я делаю не так и каков правильный путь? Я новичок в извращении.

@ moshez: Благодарю. Работает сейчас:

from twisted.internet import reactor, threads
from urlparse import urlparse
import httplib
import itertools


concurrent = 100
finished=itertools.count(1)
reactor.suggestThreadPoolSize(concurrent)

def getStatus(ourl):
    url = urlparse(ourl)
    conn = httplib.HTTPConnection(url.netloc)   
    conn.request("HEAD", url.path)
    res = conn.getresponse()
    return res.status

def processResponse(response,url):
    print response, url
    processedOne()

def processError(error,url):
    print "error", url#, error
    processedOne()

def processedOne():
    if finished.next()==added:
        reactor.stop()

def addTask(url):
    req = threads.deferToThread(getStatus, url)
    req.addCallback(processResponse, url)
    req.addErrback(processError, url)   

added=0
for url in open('urllist.txt'):
    added+=1
    addTask(url.strip())

try:
    reactor.run()
except KeyboardInterrupt:
    reactor.stop()

1 Ответ

6 голосов
/ 14 апреля 2010

Вы используете слишком много "вызовов реактора" (например, есть большая вероятность, что agent.request вызывает в реактор) из основного потока. Я не уверен, что это ваша проблема, но она все еще не поддерживается - единственные вызовы реактора, которые можно сделать из потока без реактора, это реактор.callFromThread.

Кроме того, вся архитектура кажется странной. Почему вы не запускаете реактор на главном потоке? Чтение всего файла с 10 000 запросов и разбиение их не должно быть проблемой для реактора, даже если вы делаете все это сразу.

Вероятно, вы можете использовать чисто закрученное решение без использования потоков.

...