#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)