简体   繁体   中英

Double triggering of 2 threads running parallel

my code. it starts 2 threads with inner schedulers that print number every second

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

expected output

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

actual output (see 4 instead of 2 prints at 17' and 3 instead of 2 prints at 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

I dont actually know why sometimes thread triggers function more than just once. Any idea what i do wrong ?

Both threads add a task to schedule and both threads execute run_pending() . What might be happening here is that one thread executes run_pending() causing both of the scheduled tasks to be run, but before run_pending() finishes executing in the first thread (and marking the pending tasks as completed), the second thread steps in and executes run_pending() as well, causing any pending tasks to be executed twice.

By moving the lock from the function p and putting it around run_pending() instead I was unable to replicate the behavior of tasks being fired twice.

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

Note that you could rewrite the program as well such that only one thread calls the run_pending() , something like this:

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

This is assuming you want to use the main thread for something other than running the scheduled tasks. Or you could just put a call to run_pending() in your application's event loop without having it in a separate thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM