我有一些关于使用Python和Redis创建作业队列应用程序以运行异步命令的一般性问题。这是我到目前为止生成的代码:
def queueCmd(cmd):
r_server.rpush("cmds", cmd)
def printCmdQueue():
print r_server.lrange("cmds", 0 , -1)
def work():
print "command being consumed: ", r_server.lpop("cmds")
return -1
def boom(info):
print "pop goes the weasel"
if __name__ == '__main__':
r_server = redis.Redis("localhost")
queueCmd("ls -la;sleep 10;ls")
queueCmd("mkdir test; sleep 20")
queueCmd("ls -la;sleep 10;ls")
queueCmd("mkdir test; sleep 20")
queueCmd("ls -la;sleep 10;ls")
queueCmd("mkdir test; sleep 20")
printCmdQueue()
pool = Pool(processes=2)
print "cnt:", +r_server.llen("cmds")
#while r_server.llen("cmds") > 0:
while True:
pool.apply_async(work, callback=boom)
if not r_server.lrange("cmds", 0, -1):
#if r_server.llen("cmds") == 0:
print "Terminate pool"
pool.terminate()
break
printCmdQueue()
首先,我是否相信如果我需要与经理进行任何沟通,我想通过回调做到这一点?我在此用法上看到的快速示例将异步调用存储在结果中,并通过result.get(timeout = 1)访问它。通过沟通,我的意思是把东西放回到redis列表中。
编辑:如果命令是在异步中运行而我在主内部的结果上超时,那是否会超时工作者或管理器内的操作?如果只有经理不能用它来检查工人的退出代码吗?
接下来,此代码生成以下输出:
['ls -la;sleep 10;ls', 'mkdir test; sleep 20', 'ls -la;sleep 10;ls', 'mkdir test; sleep 20', 'ls -la;sleep 10;ls', 'mkdir test; sleep 20']
command being consumed: ['mkdir test; sleep 20', 'ls -la;sleep 10;ls', 'mkdir test; sleep 20', 'ls -la;sleep 10;ls', 'mkdir test; sleep 20']
pop goes the weasel
command being consumed: ['ls -la;sleep 10;ls', 'mkdir test; sleep 20', 'ls -la;sleep 10;ls', 'mkdir test; sleep 20']
command being consumed: mkdir test; sleep 20
pop goes the weasel
pop goes the weasel
command being consumed: ['ls -la;sleep 10;ls', 'mkdir test; sleep 20']
pop goes the weasel
command being consumed: ['ls -la;sleep 10;ls', 'mkdir test; sleep 20']
command being consumed: mkdir test; sleep 20
Terminate pool
command being consumed: None
pop goes the weasel
pop goes the weasel
pop goes the weasel
[]
为什么工作人员想要一次消耗多个cmd,即使我一次只弹出一个cmd?在类似的情况下,这并不总是很好地结束,有时需要ctrl + c。为了处理他,我清理队列然后再去。我认为这与apply_sync()以及是否离开循环有关。我想知道是否需要在工人方面发生更多事情?
如果我将ifs改为注释掉的那个,我得到:
ValueError: invalid literal for int() with base 10: 'ls -la;sleep 10;ls'
这似乎是一种更好的方法来检查我是否需要中断,但似乎函数有时会返回一个字符串文字?
任何关于改善这一点的建议都将非常感激。我只是想创建一个类似Linux机器上的服务/守护进程的管理器。它将用于从redis列表中获取作业(当前是命令但可能更多),并将结果返回到redis列表中。然后,GUI将与此管理器交互以获取队列状态并返回结果。
谢谢,
编辑:
我意识到自己有点蠢蠢欲动。我不需要从worker访问redis服务器,这导致了一些错误(特别是ValueError)。
要解决此问题,现在循环:
while not r_server.llen("cmds") == 0:
cmd = r_server.lpop("cmds")
pool.apply_async(work, [cmd])
在这些行之后,我致电pool.close()
。我使用os.getpid()
和os.getppid()
来检查我确实有多个孩子跑来跑去。
如果这听起来像创建使用redis的经理/工作人员应用程序的好方法,我仍然会喜欢听。
答案 0 :(得分:2)
您的问题是您尝试使用单个redis连接同时运行多个命令。
你期待像
这样的东西Thread 1 Thread 2
LLEN test
1
LPOP test
command
LLEN test
0
但你得到了
Thread 1 Thread 2
LLEN test
1
LPOP test
LLEN test
command
0
结果以相同的顺序返回,但没有任何内容将线程或命令链接到特定结果。单个redis连接不是线程安全的 - 每个工作线程需要一个。
如果你不恰当地使用流水线操作,你也可以看到类似的问题 - 它是专为只写场景设计的,比如在列表中添加大量项目,你可以通过假设LPUSH成功而不是等待服务器告诉你它来提高性能每个项目后都成功了。 Redis仍将返回结果,但它们不一定是发送的最后一个命令的结果。
除此之外,基本方法是合理的。您可以进行一些改进: