apscheduler 不会删除作业

apscheduler does not remove job

我是 python 的初学者,在我的 tkinter 中,我有一个选项菜单,总共有 4 个选项。

选项菜单

# create tk variable
self.timervar = tk.StringVar(root)

# dropdown dictionary
self.timerDict = {"-", "5 seconds", "10 seconds", "15 seconds"}
self.timervar.set("-")  # <-- set the default value

# timer dropdown menu
self.timer_option = tk.OptionMenu(root, self.timervar, *self.timerDict, command=self.req_timer)
self.timer_option.grid(row=1, column=3, columnspan=2, padx=3, pady=3)

根据选项,函数将 运行 每 x 分钟。当我切换到另一个选项时,该功能的 apscheduler 作业将被删除,新作业将开始。

apscheduler

def req_timer(self, option):

    scheduler = apscheduler.schedulers.background.BackgroundScheduler()

    if option == "15 minutes":
        if 'job' in locals():
            job.remove_job('option_timer')
            job = scheduler.add_job(self.req_client, 'cron', second='*/15', id='option_timer')
            scheduler.start()
        else:
            job = scheduler.add_job(self.req_client, 'cron', second='*/15', id='option_timer')
            scheduler.start()

    elif option == "10 minutes":
        if 'job' in locals():
            job.remove_job('option_timer')
            job = scheduler.add_job(self.req_client, 'cron', second='*/10', id='option_timer')
            scheduler.start()
        else:
            job = scheduler.add_job(self.req_client, 'cron', second='*/10', id='option_timer')
            scheduler.start()

    elif option == "5 minutes":
        if 'job' in locals():
            job.remove_job('option_timer')
            job = scheduler.add_job(self.req_client, 'cron', second='*/5', id='option_timer')
            scheduler.start()
        else:
            job = scheduler.add_job(self.req_client, 'cron', second='*/5', id='option_timer')
            scheduler.start()

    elif option == "-":
        if 'job' in locals():
            job.remove_job('option_timer')
        else:
            pass

但在我的例子中,一旦 apscheduler 作业开始 运行ning,即使我切换到另一个应该删除作业的选项,它也不会停止。它堆叠了工作。因此,如果我 select 5 seconds 选项,它通常会 运行。但是,如果我切换到 10 seconds 选项,它将 运行 10 seconds 选项置于 5 seconds 选项之上。由于两个选项使用相同的功能,所以当 5 秒和 10 秒彼此重合时,它会给我两次相同的结果。

无论是否使用作业 ID,我都试过了,结果都一样。

这些是结果

Connecting to port...  # <-- 5 seconds option
Successfully connected to port 9998
Successfully connected to port 9999
Sending request  1 ...
Received reply  1 [ Sensor: 6 :: Data: 123456789 :: Client: 9100 ]
Sending request  2 ...
Received reply  2 [ Sensor: 7 :: Data: 987654321 :: Client: 9101 ]
Connecting to port...  # <-- at this point, the 10 seconds option was selected
Successfully connected to port 9998
Successfully connected to port 9999
Sending request  1 ...
Connecting to port...
Successfully connected to port 9998
Successfully connected to port 9999
Sending request  1 ...
Received reply  1 [ Sensor: 6 :: Data: 123456789 :: Client: 9100 ]
Sending request  2 ...
Received reply  1 [ Sensor: 6 :: Data: 123456789 :: Client: 9100 ]
Sending request  2 ...
Received reply  2 [ Sensor: 7 :: Data: 987654321 :: Client: 9101 ]
Received reply  2 [ Sensor: 7 :: Data: 987654321 :: Client: 9101 ]
Connecting to port...
Successfully connected to port 9998
Successfully connected to port 9999
Sending request  1 ...
Received reply  1 [ Sensor: 6 :: Data: 123456789 :: Client: 9100 ]  # <-- closed tkinter window
Execution of job "MainApplication.req_client (trigger: cron[second='*/5'], next run at: 2017-12-29 16:34:30 +08)" skipped: maximum number of running instances reached (1)
Execution of job "MainApplication.req_client (trigger: cron[second='*/5'], next run at: 2017-12-29 16:34:35 +08)" skipped: maximum number of running instances reached (1)
[Cancelled]

我的代码(可能是所有代码)有什么问题,如何按预期将其设置为 运行?

job 永远不会在 locals() 中,因为它是一个局部变量,并且您在设置之前正在检查它。当函数 returns 时,所有局部变量都被取消设置,因此下次调用该函数时它会再次被取消设置。

由于您似乎在使用 classes,因此您应该使用 class 变量,并将其初始化为 None

class Whatever():
    def __init__(self, ...):
        self.job = None
        ...
    def req_timer(self, option=None):
        if self.job is not None:
            ...

此外,您还有很多可以删除的重复代码。例如,您可能要考虑像这样重写函数以减少复制:

def req_timer(self, option):

    seconds_map = {
        "15 minutes": "*/15",
        "10 minutes": "*/10",
        "5 minutes": "*/5",
        "-": None,
    }

    scheduler = apscheduler.schedulers.background.BackgroundScheduler()

    if self.job is not None:
        self.job.remove_job('option_timer')
        self.job = None

    seconds = seconds_map.get(option, None)
    if seconds is not None:
        self.job = scheduler.add_job(self.req_client, 'cron',
                                     second=seconds,
                                     id='option_timer')
        scheduler.start()