взаимодействие time.sleep с threading.Lock - PullRequest
0 голосов
/ 22 октября 2019

Я пытаюсь понять блокировки в Python и написал следующий пример кода.

import threading
import time

LOCK = threading.Lock()

class Printer(threading.Thread):
    def __init__(self, *args, **kwargs):
        super(Printer, self).__init__(*args, **kwargs)
        self.daemon = True
        self.i = 0

    def run(self):
        while True:
            with LOCK:
                print(self.i)
                self.i += 1
            time.sleep(1)

raw_input('press enter to start thread\n')
Printer().start()
raw_input('press enter to pause thread\n')
LOCK.acquire()
raw_input('press enter to resume thread\n')
LOCK.release()
raw_input('press enter to exit program\n')
print('bye!')

Это работает, как ожидалось, и выдает такой результат:

press enter to start thread

0
 press enter to pause thread
1
2
3
4

press enter to resume thread

press enter to exit program
5
6
7
8

bye!

Вопрос

Почему отступ time.sleep(1) внутри блока with нарушает программу?

При

def run(self):
    while True:
        with LOCK:
            print(self.i)
            self.i += 1
            time.sleep(1)

принтер не может быть прерван!

Ответы [ 2 ]

2 голосов
/ 22 октября 2019

Измените свой код на это и посмотрите, что происходит:

import threading
import time

LOCK = threading.Lock()


class Printer(threading.Thread):
    def __init__(self, *args, **kwargs):
        super(Printer, self).__init__(*args, **kwargs)
        self.daemon = True
        self.i = 0

    def run(self):
        while True:
            with LOCK:
                print(self.i)
                self.i += 1
                time.sleep(1)


raw_input('press enter to start thread\n')
Printer().start()
raw_input('press enter to pause thread\n')
print('acquiring...')
LOCK.acquire()
print('acquired')
raw_input('press enter to resume thread\n')
LOCK.release()
raw_input('press enter to exit program\n')
print('bye!')

когда ваш код пытается запустить LOCK.acquire() Я думаю, что гонка начинается между with LOCK и LOCK.acquire() и поток выигрывает игрубольшую часть времени и приобретает LOCK на 1 секунду. Но в первом методе, когда Printer () ожидает 1 секунду, основной поток без проблем получает LOCK, потому что он бесплатный. Я надеюсь, что вы поняли. извините за мой язык:))

1 голос
/ 22 октября 2019

Hameda169 понял это!

Я написал небольшой демонстрационный графический интерфейс с кнопкой «вкл» и «выкл», чтобы объяснить / запомнить концепцию в будущем.

Если вы закомментируете time.sleep(0.01) после LOCK.release(), кнопки графического интерфейса пользователя могут долго зависать, пока они пытаются получить блокировку.

Это также показывает, зачем вообще нужны блокировки. Если вы закомментируете with LOCK в обратных вызовах on и off, вы очень скоро получите AttributeError при нажатии кнопок.

# see what happens when there's no sleep AFTER release
# see what happens if on and off functions do not acquire the lock

import Tkinter as tk
import threading
import time
import ttk

class ON(object):
    pass

class Printer(threading.Thread):
    def __init__(self, *args, **kwargs):
        super(Printer, self).__init__()
        self.daemon = True
        self.on = None
        self.i = 0

    def run(self):
        while True:
            LOCK.acquire()
            if self.on is not None: 
                time.sleep(0.1) # make it very likely that self.on can be set to
                                # None from outside before trying to access
                                # dummy_attribute -> AttributeError w/o lock!
                self.on.dummy_attribute # can error without lock
                print(self.i)
                self.i += 1
            LOCK.release()

            time.sleep(0.01) # must sleep after release, else lock can be
                             # acquired immediately again!

ROOT = tk.Tk()
PRINTER = Printer()
LOCK = threading.Lock()

def on():
    with LOCK:
        PRINTER.on = ON()
        PRINTER.on.dummy_attribute = 'foo'

def off():
    with LOCK:
        PRINTER.on = None

ttk.Button(ROOT, text='on', command=on).grid()
ttk.Button(ROOT, text='off', command=off).grid()

if __name__ == '__main__':
    PRINTER.start()
    ROOT.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...