Python 3, многопоточность - получение данных в основной модуль по завершении каждого потока - PullRequest
0 голосов
/ 20 февраля 2011

Следующий код выполняет два потока (многопоточность), каждый с разными временными задержками, поэтому каждый поток завершается в разное время.

Когда оба потока завершены, модуль display1.py выдает оператор печати, в котором говорится, что они ОБА завершены.

Я бы хотел, чтобы модуль display1.py выдал «готовый» оператор для КАЖДОГО потока, КАК КАЖДЫЙ поток завершается

Как я могу это сделать ... поправки в мой рабочий код приветствуются! Я хотел бы изменить как можно меньше текущего кода, чтобы лучше использовать метод переноса переменных между двумя модулями.

display1.py

from threads1 import *


manager = ThreadManager()
manager.start(False)

print (manager.GetResults())

threads1.py

from threading import Thread
import time

class ThreadManager:
    def __init__(self):
        pass

    def start(self, answer):
        self.answer = answer
        thread_refs = []

        t1 = MyThread(70, 'Not finished')
        t1.daemon = True
        t1.start()

        t2 = MyThread(2, 'Not finished')
        t2.daemon = True
        t2.start()

        while True:
          if t1.AskFinished == 'Finished' and t2.AskFinished == 'Finished':  #If I break the loop after EACH site, Only the first to finish will be sent via GetResults to display1.py
            global results
            results = [t1.AskFinished, t2.AskFinished]
            print("Both Finished")
            break

    def GetResults(self):
      global results
      return(results)


class MyThread(Thread):

    def __init__(self, SleepWait, AskFinished):
        Thread.__init__(self)
        self.SleepWait = SleepWait
        self.AskFinished = AskFinished


    def run(self):
        time.sleep(self.SleepWait)
        self.AskFinished = 'Finished'

Ответы [ 3 ]

2 голосов
/ 20 февраля 2011

То, что вы здесь имеете (вводя очень узкий цикл проверки в главном потоке), является очень наивным подходом к многопоточности во многих языках, но особенно в python, где конфликт GIL просто сильно замедлит потоки.

Лучше вместо этого использовать queue.Queue для отправки информации, когда поток завершен.Это позволяет основному потоку вместо этого блокировать очередь, что требует меньше ресурсов процессора, а также позволяет вам узнать (не в порядке), какой из них завершен.

Изменения, которые вам нужно будет сделать:

в верхней части модуля threads1.py:

import queue

finished_queue = queue.Queue()

при запуске ():

num_finished = 0
while True:
    info = finished_queue.get()
    num_finished += 1
    if info is t1:
        print("t1 finished")
    else:
        print("t2 finished")
    if num_finished == 2:
        global results
        results = [t1.AskFinished, t2.AskFinished]
        print("Both Finished")
        break

и, наконец, при запуске ():

def run(self):
    time.sleep(self.SleepWait)
    self.AskFinished = 'Finished'
    finished_queue.put(self)

Некоторые более фундаментальные изменения, которые я бы сделал, на самом деле помещают результат в очередь, а затем извлекают результаты, пропуская дополнительный шаг перед GetResults.Кроме того, если бы GetResults пришлось остаться, я бы пропустил их через поле на self например self.results = [t1.AskFinished, t2.AskFinished]

1 голос
/ 20 февраля 2011

Обновление

Хорошо, значит, вы хотите узнать больше о том, как display1.py распечатать результаты. Было бы полезно, если бы вы могли объяснить, почему это важно, потому что это может изменить то, как вы должны это сделать, но вот первый подход:

# threads1.py
from threading import Thread
import time

class ThreadManager:
    def __init__(self):
        self.threads = {}

    def start(self):
        t1 = MyThread(4)
        t1.daemon = True
        t1.start()
        self.threads[1] = t1

        t2 = MyThread(1)
        t2.daemon = True
        t2.start()
        self.threads[2] = t2

    def is_alive(self, thread_id):
        return self.threads[thread_id].is_alive()

    def GetResults(self):    # or you could just access results directly
        return self.results

class MyThread(Thread):
    def __init__(self, SleepWait):
        Thread.__init__(self)
        self.SleepWait = SleepWait

    def run(self):
        time.sleep(self.SleepWait)

А потом ...

* * 1010

В конечном итоге вам следует подумать об использовании Очереди в соответствии с предложением Crast; но давайте сосредоточимся на том, чтобы сделать это правильно первым.

Исходное сообщение :

Существует ряд проблем с этим кодом.

Во-первых, вы должны использовать t1.is_alive(), чтобы проверить, закончен ли поток. Нет необходимости переопределять его с AskFinished.

Во-вторых, цикл while True: в threads1.py ничего не делает со скоростью неистово , пока он ожидает завершения ваших потоков. Посмотрите на использование процессора, пока оно работает, если вы мне не верите. Вы должны добавить туда time.sleep(1) оператор.

В-третьих, почему вы используете глобальную переменную для возврата результатов? Это действительно странная вещь. Просто храните это в себе!

И, наконец, почему display1.py должен печатать сообщения? Почему thread1.py не может это сделать?

Имея в виду эти четыре момента, вот thread1.py, которое работает более разумно:

from threading import Thread
import time

class ThreadManager:
    def __init__(self):
        self.results = None

    def start(self, answer): # why is "answer" here?
        self.answer = answer
        thread_refs = []

        t1 = MyThread(4, 'Not finished')
        t1.daemon = True
        t1.start()

        t2 = MyThread(1, 'Not finished')
        t2.daemon = True
        t2.start()

        t1_state = t2_state = True
        while t1.is_alive() or t2.is_alive():
          time.sleep(1)
          if t1.is_alive() != t1_state:
            print("t1 finished")
            t1_state = t1.is_alive()
          if t2.is_alive() != t2_state:
            print("t2 finished")
            t2_state = t2.is_alive()
          if not t1.is_alive() and not t2.is_alive():
            self.results = [t1.AskFinished, t2.AskFinished]
            print("Both Finished")
            break

    def GetResults(self):    # or you could just access results directly
        return self.results


class MyThread(Thread):

    def __init__(self, SleepWait, AskFinished):
        Thread.__init__(self)
        self.SleepWait = SleepWait
        self.AskFinished = AskFinished


    def run(self):
        time.sleep(self.SleepWait)
        self.AskFinished = 'Finished'

Теперь, это все еще не делает точно, что вы хотели, потому что вы попросили display.py сделать отображение. Чтобы это работало, вам нужно поместить цикл while True в display.py и добавить метод ThreadManager.is_alive(), который display.py может использовать для проверки, является ли поток живым или нет. Если вы хотите увидеть, как это сделать, дайте мне знать.

0 голосов
/ 20 февраля 2011

Я не знаком с многопоточностью, но, поскольку пока нет ответов, я не могу дать ему шанс.

В этом: Не могли бы вы просто добавить два оператора if перед рукой?

    while True:
      if t1.askFinished == 'Finished':
         print("t1 Finished")
      if t2.askFinished == 'Finished':
         print("t2 Finished")
      if t1.AskFinished == 'Finished' and t2.AskFinished == 'Finished':  #If I break the loop after EACH site, Only the first to finish will be sent via GetResults to display1.py
        global results
        results = [t1.AskFinished, t2.AskFinished]
        print("Both Finished")
        break

edit: я пытался изменить ваш код как можно меньше ... он написан не очень хорошо, хотя tbh. (Без обид)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...