А вот и еще одна дискуссия о GIL. Ну, вот в чем дело. Выборка контента с urllib2 будет в основном IO-привязана. Собственные потоки и многопроцессорность будут иметь одинаковую производительность, когда задача связана с вводом-выводом (многопоточность становится проблемой только тогда, когда она связана с процессором). Да, вы можете ускорить это, я сделал это сам, используя потоки Python и что-то вроде 10 потоков загрузчика.
В основном вы используете модель производитель-потребитель с одним потоком (или процессом), создающим URL-адреса для загрузки, и N потоков (или процессов), потребляющих из этой очереди и выполняющих запросы к серверу.
Вот некоторый псевдокод:
# Make sure that the queue is thread-safe!!
def producer(self):
# Only need one producer, although you could have multiple
with fh = open('urllist.txt', 'r'):
for line in fh:
self.queue.enqueue(line.strip())
def consumer(self):
# Fire up N of these babies for some speed
while True:
url = self.queue.dequeue()
dh = urllib2.urlopen(url)
with fh = open('/dev/null', 'w'): # gotta put it somewhere
fh.write(dh.read())
Теперь, если вы загружаете очень большие порции данных (сотни МБ) и один запрос полностью насыщает полосу пропускания, тогда да, запуск нескольких загрузок не имеет смысла. Причина, по которой вы запускаете несколько загрузок (как правило), заключается в том, что запросы небольшие и имеют относительно высокую задержку / накладные расходы.