Вызов метода, отличного от запуска в потоке - PullRequest
0 голосов
/ 25 января 2019

Я изучаю многопоточность в Python, и меня смущает следующий код, который я написал. Как после запуска потока Heartbeat вызов метода stuff работает относительно метода run? Есть ли какое-либо состояние гонки в отношении i, и если да, то как бы я мог это предотвратить?

Мне интересно, можно ли эффективно использовать этот тип конструкции для связи с потоком. Я не понимаю, как это работает под капотом, однако, с точки зрения вызовов методов в классе Heartbeat после активации run. Я предполагаю, что sleep позволяет stuff выполнить, но я не знаю почему. Возможно, я слишком усложняю это и упускаю что-то очевидное; мое отсутствие интуиции, однако, тревожит. Буду признателен за любую помощь или совет.

   1 import threading
   2 import time
   3 
   4 class Heartbeat(threading.Thread):
   5   def __init__(self, delay):
   6     threading.Thread.__init__(self, daemon = True)
   7     self.delay = delay
   8     self.i = 0
   9   
  10   def run(self):
  11     while True:
  12       print("i = {}".format(self.i))
  13       time.sleep(self.delay)
  14   
  15   def stuff(self, i):
  16     self.i = i
  17 
  18 if __name__ == "__main__":
  19   hbThread = Heartbeat(3)
  20   hbThread.start()
  21   
  22   i = 0
  23   while True:
  24     time.sleep(1)
  25     i += 1
  26     hbThread.stuff(i)

И вывод:

i = 0
i = 2
i = 5
i = 8
i = 11

Редактировать: По моему мнению, этот вопрос отличается от предложенного дублирующего вопроса по нескольким причинам. Это гораздо более простой вопрос с очень конкретным вопросом, тогда как другой является широким вопросом о многопоточности в целом. Ответы очень полезны, но я не вижу ни одного, объясняющего внутреннюю работу моей ситуации, и не было объяснения того, как другие методы вызываются из другого потока, насколько я могу судить. Если это так, то новичок может быть не в состоянии полностью понять; этот вопрос проще и точнее, так что я думаю, что он имеет место.

1 Ответ

0 голосов
/ 25 января 2019

Когда вы наследуете от Thread, ваш экземпляр будет похож на человека, стоящего одной ногой на кухне и одной ногой в гостиной. В каком потоке будет выполняться метод, зависит от того, из какого потока вы его вызываете. run будет главной функцией в новом потоке, и каждый вызываемый им метод будет выполняться там. Если вы позвоните stuff от родителя, он будет запущен в MainThread. Из-за GIL одновременно может работать только один поток. Поток в Python 3 будет хранить GIL (и, следовательно, сможет выполнять код Python) по умолчанию на срок до 5 мс или сбрасывать его раньше при блокировке ввода-вывода (например, time.sleep). Все потоки в процессе совместно используют одну и ту же память, поэтому вы можете добавить к экземпляру из нового потока и из MainThread, и оба будут иметь доступ к данным.

...