van-gog
Апрель 25, 2008 15:30:46
Доброго времени суток!
У меня возникла проблема с Twisted.internet.threads
есть код:
…..
def getData(url):
res = getPage(url)
return
def resCallBack(data):
print data
reactor.stop()
d = threads.deferToThread(getData, ‘some site’)
d.addCallback(resCallBack)
reactor.run()
После работы этого скрипта мне выдает следующее:
<Deferred at 0xfd1878>
Но по идее должно выдать код страницы…
В чем проблема ?
ЗЫ: в гугле смотрел…
Андрей Светлов
Апрель 25, 2008 16:51:03
Все правильно.
twisted.web.getPage возвращает именно deferred, который ты и видишь - это раз.
getPage не может быть вызвана из потока - только из реактора (есть хитрые возможности, но они сейчас не интересны). deferToThread делали не для твоего случая. Это два.
van-gog
Апрель 25, 2008 17:02:00
Андрей Светлов
Все правильно.
twisted.web.getPage возвращает именно deferred, который ты и видишь - это раз.
getPage не может быть вызвана из потока - только из реактора (есть хитрые возможности, но они сейчас не интересны). deferToThread делали не для твоего случая. Это два.
А для каких целей делали deferToThread?
И каким образом это можно обойти, если не секрет?
Андрей Светлов
Апрель 25, 2008 18:14:26
deferToThread нужен для выполнения долгих операций, не знающих о реакторе, в пуле потоков (в отдельном потоке, для простоты понимания). Примеры таких операций - “длинные” обращения к базе данных, выполнение долгих вычислений.
У тебя другой случай. Нужно делать
def onPage(page):
print page
def stopReactor(arg):
reactor.stop()
d = getPage('some site')
d.addCallback(onPage).addCallback(stopReactor)
reactor.run()
Остановка реактора после получения странички - только для теста, конечно же. Реактор должен работять всю жизнь приложения.
van-gog
Апрель 25, 2008 18:49:32
Мне как раз нужно чтобы страничка скачивалась в потоке, и из потока вызывался колбек.
В моем случае сраничка содержит ооочень много записей, и таких страничек за определенный промежуток времени нужно обработать несколько.
На скачку одной страницы уходит приблизительно 6-10 секунд.
Андрей Светлов
Апрель 25, 2008 19:25:05
Вариант 2
.....
def getData(url):
page = urllib2.urlopen(url)
body = page.read()
# process page
ret = process(body)
return [url, res]
def resCallBack(data):
print data[1]
reactor.stop()
d = threads.deferToThread(getData, 'some site')
d.addCallback(resCallBack)
reactor.run()
Третий вариант - переписать twisted.web.client.HTTPClientFactory, чтобы вытягивала и обрабатывала страничку по частям. Это - сложнее.
van-gog
Май 7, 2008 16:49:09
Спасибо за ответ :)
Теперь возник другой вопрос:
как запустить одновременно 10 потоков, каждый из которых после выполнения добавляет в список задач новую задачу, и она уже, если количество потоков < 10, тоже запускается в отдельном потоке.
Я сделал так:
def run():
if len(threads) < 10:
if len(tasks) == 0:
reactor.stop()
pass
else:
if len(tasks) > 0:
function, params, callback = tasks.pop(0)
threads.deferToThread(function, params).addCallback(callback)
reactor.run()
threads.append(params)
sleep(.1) #чтоб не слишком загружать процессор
Но этот кусок кода работает не совсем правильно :(
Первое задание выполняется, а остальные - нет :(
Помогите пожалуйста.
ЗЫ: гугл ответа не дал :(
Андрей Светлов
Май 7, 2008 18:14:42
:)
Ты должен просто ничего не делать.
реактор уже содержит пул потоков. С максимальным размером именно в 10 штук.
Поэтому просто бомби threads.deferToThread сколько хочешь раз. Больше десяти одновременно выполняться не будет.
sleep - тоже не нужен. У тебя реактор должен все время крутиться.
Код инициализации пула в twisted.internet.base:_initThreadPool
сам пул в twisted.python.threadpool
van-gog
Май 8, 2008 16:14:39
Андрей Светлов
:)
Ты должен просто ничего не делать.
реактор уже содержит пул потоков. С максимальным размером именно в 10 штук.
Поэтому просто бомби threads.deferToThread сколько хочешь раз. Больше десяти одновременно выполняться не будет.
sleep - тоже не нужен. У тебя реактор должен все время крутиться.
Код инициализации пула в twisted.internet.base:_initThreadPool
сам пул в twisted.python.threadpool
Спасибо, все заработало :)
van-gog
Май 14, 2008 18:47:43
Здравствуйте еще раз :)
Теперь возник такой вопрос: как сделать чтоб ссылки, которые я передаю в threads.daferToThread скачивались через равное количество времени, н-р 1с. (ато сервер сильно грузит)
Зарание спасибо
ЗЫ: пробовал sleep - не реагирует