Есть ли способ вызвать метод потока объектов класса и запустить его в этом конкретном потоке?

#python #multithreading #dictionary #oop #python-multithreading

#python #многопоточность #словарь #ооп #python-многопоточность

Вопрос:

Контекст:

У меня есть класс потоков, который вызывается 10 раз в цикле for .

Для каждого объекта класса я передаю username для пользователя, который определяется его местом в цикле for , например user0, user1, user2 , ect.

Я создал метод, вызываемый new_message() в классе, который просто печатает другое сообщение.

В def run() методе класса я добавил ключ username as и new_message() функцию в качестве значения в словарь

Моя проблема:

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

Итак, мой вопрос:

Есть ли способ вызвать метод потока объектов класса и запустить его в этом конкретном потоке?


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

Код:

 import time

import threading

dict = {

}

class go(threading.Thread):
    def __init__(self, username):
        threading.Thread.__init__(self)
        self.username = username

    def run(self):
        dict[self.username] = self.new_message
        for count in range(10):
            print('Hello: ' self.username 'n')
            time.sleep(10)

    def new_message(self):
        for count in range(10):
            print('How are you: ' self.username)
            time.sleep(2)


for count in range(10):
    username = ('user'   str(count))
    go(username).start()


what_user = input('What user')
dict[what_user]()

Print('This line shouldn't be waiting to print')

  

Ответ №1:

Есть ли способ вызвать метод потока объектов класса и запустить его в этом конкретном потоке?

Нет, это невозможно. Вы уже start() отредактировали поток, что заставляет его запускать свой run() метод. Вы не можете вызвать подобный метод, чтобы запустить его в этом конкретном потоке — он просто будет выполняться в потоке, который его вызвал, как вы заметили (он выполнялся в вашем основном потоке).

Вам нужно, чтобы другие потоки (назовем их рабочими потоками) сотрудничали с внешними задачами, чтобы это произошло. Например, вы можете заставить рабочие потоки прослушивать рабочую очередь после выполнения начальной работы, чтобы Получать задачи (т. Е. Функции) и запускать их.

Вот быстрая реализация вашего кода:

 import time

import threading
from queue import Queue

dict = {}


class Go(threading.Thread):
    def __init__(self, username, work_queue):
        threading.Thread.__init__(self)
        self.username = username
        self.work_queue = work_queue

    def run(self):
        self.initialize()
        while True:
            task = self.work_queue.get()
            task()
            self.work_queue.task_done()

    def initialize(self):
        dict[self.username] = {"func": self.new_message, "queue": self.work_queue}
        for _ in range(10):
            print("Hello: "   self.username   "n")
            time.sleep(10)

    def new_message(self):
        for _ in range(10):
            print("How are you: "   self.username)
            time.sleep(2)


for count in range(10):
    username = "user"   str(count)
    Go(username, Queue()).start()


what_user = input("What user")
selection = dict[what_user]
queue, method = selection["queue"], selection["func"]
queue.put(method)

print("This line shouldn't be waiting to print")
  

Вы заметите, что "This line shouldn't be waiting to print" indeed теперь не будет ждать. Основной поток помещает его в качестве задачи в очередь для выбранного рабочего потока. Рабочий выбирает это, как только это будет сделано с его self.initialize() вызовом.

Комментарии:

1. Это сработало потрясающе, я просто смущен тем, как цикл while смог запуститься, когда self.initialize он не был завершен

2. Он не запускался раньше — он запускался после self.initialize . Тем временем другая «задача» просто ожидает в очереди. Целевой поток забирает его, как только с ним покончено self.initialize() . Если вы хотите, чтобы он остановил то, что он делает, вам нужно будет добавить некоторую условную логику, чтобы прервать этот начальный цикл while.

3. Я очень смущен, я понимаю, что self.initialize он запускается первым, но цикл while, я не понимаю, как его выполнение или даже вызов, тем более self.initialize , что для завершения требуется некоторое время

4. self.initialize выполняется в течение 100 секунд в рабочих потоках ( не в основном потоке). Когда-нибудь в течение этого времени вы выбираете пользователя; в этот момент основной поток помещает задачу в целевую очередь. Рабочий поток через 100 секунд просматривает очередь и видит задачи, ожидающие его там. Он подбирает его и запускает (т. Е. Запускает new_message функцию).

5. Я вижу, что теперь понимаю, так что нет способа запустить его сразу def new_message(self)