如何使用python schedule模块与共享作业队列并行执行作业时传递参数

时间:2016-04-18 08:13:29

标签: python python-2.7 queue scheduled-tasks scheduler

我打算并行运行多个作业,并使用作业队列跟随示例here,但是当我尝试传递参数时,它执行了一次并引发异常'NoneType' object is not callable。下面列出的代码:

import Queue
import schedule
import threading
import time

def job(arg):
    print 'Argument is %s' % arg

def worker_main():
    while True:
        try:
            job_func = jobqueue.get()
            job_func()
        except Exception as e:
            print e

jobqueue = Queue.Queue()

schedule.every(2).seconds.do(jobqueue.put, job(1))
schedule.every(2).seconds.do(jobqueue.put, job(2))

worker_thread = threading.Thread(target=worker_main)
worker_thread.start()

while True:
    try:
        schedule.run_pending()
        time.sleep(1)
    except Exception as e:
        print e
        sys.exit()

输出结果为:

Arg is 1
Arg is 2
'NoneType' object is not callable
'NoneType' object is not callable
'NoneType' object is not callable
'NoneType' object is not callable
'NoneType' object is not callable
'NoneType' object is not callable
...

有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

原因是do中传递给schedule.every(2).seconds.do(jobqueue.put, job(1))方法的参数实际上是None

因为代码正在调用job函数并将1(和2)作为参数传递给job。因此,job函数的返回值(因为它只是打印时为None)作为第二个参数传递给do方法调用。因此,None实例存储在作业队列中而不是函数引用。

将参数传递给作业的问题是来自do包的schedule方法可以接受要运行的作业的额外参数,但是正在安排的是将作业放入队列和队列项只是没有额外参数的函数引用。

一种解决方案是将作业与其参数一起放入队列。然后,worker需要通过将参数传递给它来获取它们并调用该作业。像这样:

import Queue
import schedule
import threading
import time

def job(arg):
    print 'Argument is %s' % arg

def worker_main():
    while True:
        try:
            job_func, job_args = jobqueue.get()
            job_func(*job_args)
        except Exception as e:
            print e

jobqueue = Queue.Queue()

schedule.every(2).seconds.do(jobqueue.put, (job, [1]))
schedule.every(2).seconds.do(jobqueue.put, (job, [2]))

worker_thread = threading.Thread(target=worker_main)
worker_thread.start()

while True:
    try:
        schedule.run_pending()
        time.sleep(1)
    except Exception as e:
        print e
        sys.exit()

这里我们将一个作业函数引用的元组和一个参数列表放到队列中。 然后工作人员将获取它们,并将参数列表传递给作业函数。

另一种解决方案是将作业(job(1)job(2)调用)包装在不需要参数的其他函数中,然后将这些函数注册到作业队列,如下所示:

def job1():
    job(1)

def job2():
    job(2)

jobqueue = Queue.Queue()

schedule.every(2).seconds.do(jobqueue.put, job1)
schedule.every(2).seconds.do(jobqueue.put, job2)