Двойной запуск двух параллельных потоков - PullRequest
1 голос
/ 26 марта 2020

мой код он запускает 2 потока с внутренними планировщиками, которые печатают номер каждую секунду

import threading
import time
from datetime import datetime

import schedule

_lock = threading.Lock()


def p(number):
    _lock.acquire()
    print(number, datetime.now())
    _lock.release()


def f(number):
    schedule.every(5).seconds.do(p, number)
    while True:
        schedule.run_pending()
        time.sleep(1)


thread = threading.Thread(target=f, args=(1,))
thread2 = threading.Thread(target=f, args=(2,))
thread.start()
thread2.start()

ожидаемый вывод

1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:22.821887
2 2020-03-25 22:07:22.821887
1 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093

фактический вывод (см. 4 вместо 2 отпечатков на 17 'и 3 вместо 2 отпечатков на 27 ')

1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:17.817528
2 2020-03-25 22:07:17.817528
1 2020-03-25 22:07:22.821887
2 2020-03-25 22:07:22.821887
1 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093
2 2020-03-25 22:07:27.826093

На самом деле я не знаю, почему иногда триггеры потока работают более одного раза. Есть идеи, что я делаю не так?

1 Ответ

1 голос
/ 26 марта 2020

Оба потока добавляют задачу к schedule, и оба потока выполняют run_pending(). Здесь может произойти то, что один поток выполняет run_pending(), вызывая выполнение обеих запланированных задач, но до того, как run_pending() завершит выполнение в первом потоке (и помечая отложенные задачи как выполненные), второй поток вступает в выполняет также run_pending(), в результате чего любые отложенные задачи выполняются дважды.

Переместив блокировку из функции p и поместив ее вокруг run_pending(), я не смог повторить поведение запускаемых дважды задач.

def f(number):
    schedule.every(5).seconds.do(p, number)
    while True:
        _lock.acquire()
        schedule.run_pending()
        _lock.release()
        time.sleep(1)

Обратите внимание, что вы могли переписать программу так, чтобы только один поток вызывал run_pending(), что-то вроде этого:

import threading
import time
from datetime import datetime

import schedule

def p(number):
    print(number, datetime.now())

schedule.every(5).seconds.do(p, 1)
schedule.every(5).seconds.do(p, 2)

def task_runner():
    while True:
        schedule.run_pending()
        time.sleep(1)

thread = threading.Thread(target=task_runner)
thread.start()

Это предполагает, что вы хотите использовать основной поток для чего-то другого, кроме выполнения запланированных задач. Или вы можете просто вызвать run_pending() в событии вашего приложения l oop, не добавляя его в отдельный поток.

...