2015-09-29 2 views
0

Я экспериментирую с многопоточным в первый раз. Я использую 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), я могу предотвратить это, но это хакерский подход. И я также обеспокоен тем, что это может означать, что если две загрузки совпадают с той же раздельной секундой, это произойдет снова.

Есть ли способ фактически обеспечить разделение здесь, чтобы я не получил эту проблему? Я слышал, что вы не должны обрабатывать пользовательские интерфейсы, это обычно происходит в контексте чего-то вроде перерисовки индикатора выполнения. Также я не уверен, есть ли удобный способ отметить, когда элемент из очереди был занят потоком, но, возможно, я пропустил его.

ответ

2

У вас есть очередь с одним потоком (назовите его консольным потоком), который отвечает за запись сообщений. Чтобы написать что-то, сгенерированное на выходе, поместите его в очередь, и консольный поток правильно напишет, когда он доберется до него.

Таким образом, существует одна тема, ответственная за запись информации на консоль, и вы можете точно контролировать, как следует выводить данные.

+0

Это интересное решение, похоже, было бы немного неудобно и трудно читать. Вы знаете, что это общий подход к обработке пользовательского интерфейса из потоков? – SuperBiasedMan

Смежные вопросы