问题:我需要控制foreach循环并行处理任务的执行顺序。不幸的是,foreach不支持这一点。
解决方案:使用doRedis使用数据库来保存在foreach循环中执行的所有任务。要控制顺序,我想通过setGetTask覆盖getTask,以根据预先指定的顺序获取任务。虽然我找不到很多关于如何做到这一点的文档。
其他信息:
setGetTask上有一个小段落,redis documentation中有一个例子。
getTask <- function ( queue , job_id , ...)
{
key <- sprintf("
redisEval("local x=redis.call('hkeys',KEYS[1])[1];
if x==nil then return nil end;
local ans=redis.call('hget',KEYS[1],x);
redis.call('hdel',KEYS[1],x);i
return ans",key)
}
setGetTask(getTask)
我认为文档中的代码在语法上是不正确的(缺少imho a&#34;以及结束括号&#34;)&#34;)。我认为这在CRAN上是不可能的,因为文档的代码是在提交时执行的。
更改getTask函数不会改变任何关于worker获取任务的内容(即使将明显的无意义引入redisEval,如将其更改为redisEval(&#34; dddddddddd((&#34; )
我从源代码安装软件包之后才能访问setGetTask函数(我从official CRAN package page of version 1.1.1下载了这个函数(这与我直接从CRAN安装没什么区别)
< / LI> 醇>数据:要执行的任务的数据框如下所示:
taskName;taskQueuePosition;parameter1;paramterN
taskT;1;val1;10
taskK;2;val2;8
taskP;3;val3;7
taskA;4;val4;7
我想使用&#39; taskQueuePosition&#39;为了控制订单,应首先执行数字较小的任务。
问题:
代码(便于复制):
以下假设redis-server在本地计算机上启动。
Redis数据库填充:
library(doRedis)
library(foreach)
options('redis:num'=TRUE) # needed for proper execution
REDIS_JOB_QUEUE = "jobs"
registerDoRedis(REDIS_JOB_QUEUE)
# filling up the data frame
taskDF = data.frame(taskName=c("taskT","taskK","taskP","taskA"),
taskQueuePosition=c(1,2,3,4),
parameter1=c("val1","val2","val3","val4"),
parameterN=c(10,8,7,7))
foreach(currTask=iter(taskDF, by='row'),
.verbose = T
) %dopar% {
print(paste("Executing task: ",currTask$taskName))
Sys.sleep(currTask$parameterN)
}
removeQueue(REDIS_JOB_QUEUE)
工人:
library(doRedis)
REDIS_JOB_QUEUE = "jobs"
startLocalWorkers(n=1, queue=REDIS_JOB_QUEUE)
答案 0 :(得分:0)
我可以解决问题,现在可以控制任务执行的顺序。
其他信息:
1。文档中似乎存在拼写错误,导致getTask示例无法正常工作。通过考虑包中文件task.R的default_getTask函数的形式,它应该看起来像:
getTaskDefault <- function ( queue , job_id , ...)
{
key <- sprintf("%s:%s",queue, job_id)
return(redisEval("local x=redis.call('hkeys',KEYS[1])[1];
if x==nil then return nil end;
local ans=redis.call('hget',KEYS[1],x);
redis.call('set', KEYS[1] .. '.start.' .. x, x);
redis.call('hdel',KEYS[1],x);
return ans",key))
}
似乎第一个百分号后面的字母在函数的第一行中丢失了。这可以解释括号和引号的数量不均匀。
2) setGetTask对我没有任何影响。当我填充DB时,通过.option设置getTask函数(就像在vignette of the package中描述的那样),它被成功调用。
3) 2)的信息意味着我不需要getTask函数,所以我可以使用CRAN中的包。
-----问题-----
1) doRedis插图描述了如何成功设置自定义getTask。
2和3)当getTask函数中的LUA脚本被修改如下时,任务将以提交方式从数据库中提取。这不是我要求的,但由于时间限制和我(或更好)没有关于LUA脚本的第一个想法的事实,它是一个令人满意的解决方案来控制taskQueuePosition列的提交顺序。
getTaskInOrder <- function ( queue , job_id , ...)
{
key <- sprintf("%s:%s",queue, job_id)
return(redisEval("
local tasks=redis.call('hkeys',KEYS[1]); -- get all tasks
local x=tasks[1]; -- get first task available task
if x==nil then -- if there are no tasks left, stop processing
return nil
end;
local xMin = 65535; -- if we have more tasks than 65535, getting the
-- task with the lowest taskID is not guaranteed to be the first one
local i = 1;
-- local iMinFound = -1;
while (x ~= nil) do -- search the array until there are no tasks left
-- print('x: ',x)
local xNum = tonumber(x);
if(xNum<xMin) then
xMin = xNum;
-- iMinFound = i;
end
i=i+1;
-- print('i is now: ',i);
x=tasks[i];
end
-- print('Minimum is task number',xMin,' found at i ', iMinFound)
x=tostring(xMin) -- convert it back to a string (maybe it would
-- be better to keep the original string somewhere,
-- in case we loose some information whilst converting to number)
-- print('x is now:',x);
-- print(KEYS[1] .. '.start.' .. x, x);
-- print('');
local ans=redis.call('hget',KEYS[1],x);
redis.call('set', KEYS[1] .. '.start.' .. x, x);
redis.call('hdel',KEYS[1],x);
return ans",key))
}
重要说明: 我注意到,如果任务中止,订单被搞砸,重新提交的任务(即使任务编号保持不变),也会在最初提交的任务之后执行。这对我来说没问题。
------代码(为了便于复制):------
这导致了以下代码示例(在任务数据框中有12个条目,而不是原始的4个):
Redis数据库填充:
library(doRedis)
library(foreach)
options('redis:num'=TRUE) # needed for proper execution
REDIS_JOB_QUEUE = "jobs"
getTaskInOrder <- function ( queue , job_id , ...)
{
...like above
}
registerDoRedis(REDIS_JOB_QUEUE)
# filling up the data frame already in order of tasks to be executed
# otherwise the dataframe has to be sorted by taskQueuePosition
taskDF = data.frame(taskName=c("taskA","taskB","taskC","taskD","taskE","taskF","taskG","taskH","taskI","taskJ","taskK","taskL"),
taskQueuePosition=c(1,2,3,4,5,6,7,8,9,10,11,12),
parameter1=c("val1","val2","val3","val4","val1","val2","val3","val4","val1","val2","val3","val4"),
parameterN=c(5,5,5,4,4,4,4,3,3,3,2,2))
foreach(currTask=iter(taskDF, by='row'),
.verbose = T,
.options.redis = list(getTask = getTaskInOrder
) %dopar% {
print(paste("Executing task: ",currTask$taskName))
Sys.sleep(currTask$parameterN)
}
removeQueue(REDIS_JOB_QUEUE)
工人:
library(doRedis)
REDIS_JOB_QUEUE = "jobs"
startLocalWorkers(n=1, queue=REDIS_JOB_QUEUE)
另一个注意事项:以防您正在处理长时间工作,请注意a bug in redis 1.1.1(CRAN上的当前版本),这会导致重新提交任务(由于尽管工人们还在为他们工作,但是暂停了。