Я экспериментирую с многопоточным в первый раз. Я использую Queue.Queue
и помещаю данные туда после того, как создал набор объектов, которые наследуют от threading.Thread
. Скрипт загружает серию файлов и работает отлично, я загружаю его, и он оказался намного быстрее, чем мой старый.Несколько нитей печати смешанных
Однако мой поток начинается с команды печати, чтобы показать, что она начала загрузку. Просто «Загрузка C: \ foo.bar». Когда очередь создается сначала, все эти команды печати склеиваются, а затем появляются новые строки.
Вот основная идея кода вовлеченного:
import Queue
import threading
queue = Queue.Queue()
class ThreadDownload(threading.Thread):
"""Threaded Download"""
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
data = self.queue.get()
print ("Downloading {}".format(data))
#download_file(data)
time.sleep(10)
self.queue.task_done()
for i in range(4):
t = ThreadDownload(queue)
t.setDaemon(True)
t.start()
#for d in data:
for d in range(20):
queue.put(d)
queue.join()
Обратите внимание, что download_file
является функцией от 3-сторонней библиотеки, что люди вряд ли знают или имеют легкий доступ к таким образом, я оставил его в пользу людей, которые откладывают некоторые другие трудоемкие призывы к их тестированию. Аналогично, с data
, форма данных не имеет отношения к вопросу, поэтому вместо этого я предлагаю людям использовать range
, чтобы легко протестировать.
Вот что выход может выглядеть следующим образом:
Downloading C:\foo.barDownloading C:\foo.barDownloading C:\foo.barDownloading C:\foo.bar
Downloading C:\foo.bar
Downloading C:\foo.bar
Downloading C:\foo.bar
Причина, кажется, из-за того, что эти нити начинают свой бег одновременно. Если я добавлю time.sleep(0.01)
, я могу предотвратить это, но это хакерский подход. И я также обеспокоен тем, что это может означать, что если две загрузки совпадают с той же раздельной секундой, это произойдет снова.
Есть ли способ фактически обеспечить разделение здесь, чтобы я не получил эту проблему? Я слышал, что вы не должны обрабатывать пользовательские интерфейсы, это обычно происходит в контексте чего-то вроде перерисовки индикатора выполнения. Также я не уверен, есть ли удобный способ отметить, когда элемент из очереди был занят потоком, но, возможно, я пропустил его.
Это интересное решение, похоже, было бы немного неудобно и трудно читать. Вы знаете, что это общий подход к обработке пользовательского интерфейса из потоков? – SuperBiasedMan