#python #python-3.x #multithreading
#python #python-3.x #многопоточность
Вопрос:
Я хочу контролировать доступ к функции на основе времени, прошедшего с момента последнего доступа.
Для этой цели я реализовал следующий декоратор, который отлично работает при выполнении одного потока:
import time
MIN_ELAPSED_TIME = 0.4
time_last_get = time.time()
def timingRequests(f):
def wrapper(*args, **kwargs):
global time_last_get
elapsed_time_since_last_get = time.time() - time_last_get
if elapsed_time_last_request < MIN_REQUEST_TIME: # not enough time has passed since the last request
time.sleep(MIN_REQUEST_TIME - elapsed_time_last_request)
# At this point, at least MIN_ELAPSED_TIME has passed since last get
time_last_get = time.time()
r = f(*args, **kwargs)
return r
return wrapper
@timingRequests
doGet()
Я хочу, чтобы n потоков (на данный момент 2) обращались к этой функции И учитывали time_last_get между потоками. Моя проблема в том, что каждый поток ожидает выполнения doGet() на основе своего предыдущего выполнения doGet()
Я пытался использовать многопоточность.Событие() как семафор, потоковая передача.Lock() но все равно оба потока обращаются к функции почти одновременно.
Поведение при использовании 2 или более потоков заключается в том, что каждый поток ожидает выполнения doGet() на основе time_last_get этого же потока, вместо этого принимая во внимание доступ других потоков.
Поведение, которого я хочу достичь, является следующим:
Поток-1: doGet()
Поток-2: ожидает (при необходимости) секунды MIN_ELAPSED_TIME, прошедшие с момента обращения к потоку-2
Поток-2: doGet()
Поток-1: ожидает (при необходимости) секунды MIN_ELAPSED_TIME, прошедшие с момента обращения к потоку-2
Поток-1: doGet()
Поток-1: ожидает (при необходимости) секунды MIN_ELAPSED_TIME, прошедшие с момента обращения к потоку-1
Ответ №1:
Я понял, в чем проблема.
Во-первых, я обошел проблему с помощью многопоточности.Экземпляры Events():
import time
MIN_ELAPSED_TIME = 0.4
time_last_get = time.time()
e = threading.Event()
e.set()
def timingRequests(f):
def wrapper(*args, **kwargs):
e.wait()
e.clear()
global time_last_get
elapsed_time_since_last_get = time.time() - time_last_get
if elapsed_time_last_request < MIN_REQUEST_TIME: # not enough time has passed since the last request
time.sleep(MIN_REQUEST_TIME - elapsed_time_last_request)
# At this point, at least MIN_ELAPSED_TIME has passed since last get
time_last_get = time.time()
r = f(*args, **kwargs)
e.set()
return r
return wrapper
@timingRequests
doGet()
Но я все еще пытался понять, почему это решение работает, но не использует блокировку.
Ну, проблема была в этом:
def timingRequests(f):
def wrapper(*args, **kwargs):
with threading.Lock():
# Code
Каждый поток, достигающий этой части кода, создавал (разблокированный) экземпляр threading .Lock() , поэтому блокировка работала не так, как ожидалось. Тогда решение состоит в том, чтобы создать блокировку вне функции timingRequests и использовать ее таким образом:
lock = threading.Lock()
def timingRequests(f):
def wrapper(*args, **kwargs):
with lock:
# Code