与doseq(或for)并行处理集合的有效方法?

Mar*_*ars 5 clojure

(doseq [e coll1]
  (myfunc e))
Run Code Online (Sandbox Code Playgroud)

非常快,如果你关心的都是副作用.如果我想myfunc"并行"从多个集合中获取元素,即应用于myfunc每个集合的第一个元素,然后应用于所有第二个元素,然后应用于所有第三个元素等,该怎么办?请注意,这同样是关于foras 的功能的问题doseq,但是如果想要一个序列作为输出,那么map就会做所需的事情,所以for没有必要.

(doseq [e1 coll1
        e2 coll2]
   (myfunc e1 e2))
Run Code Online (Sandbox Code Playgroud)

将改为应用于myfunc两个集合中所有可能的元素组合.如果我事先知道集合的元素是什么,我可以使用:when测试来仅合并某些元素,但是假设我不知道这个?

一种解决方案是创建ntuples以避免使用笛卡尔积,但这非常耗时,从而消除doseq了首先使用的速度优势:

(let [argvecs (map vector coll1 coll2)] ; seq of ntuples of interleaved vals
  (doseq [args argvecs]
     (apply myfunc args))))
Run Code Online (Sandbox Code Playgroud)

(这可能比单个集合慢大约8 doseq倍.查看此问题的时间domap1domap17结尾.)

ama*_*loy 4

如果您想避免使用映射创建元组的开销,您所能做的就是自己编写它,作为手动遍历每个集合的循环/递归。但实际上,您最终仍然需要创建一个元组,以便您可以(apply f args),其中args是每个集合的第 n 个项目。通过不创建此类元组的列表,您可以节省一些缺点单元格,但仅此而已。像这样的可变参数函数的很多开销是调用apply,并构建列表来执行此操作。你可以通过编写你的doseq-sibling的2元版本和3元版本来避免这种情况,并且......但是n元版本总是会更慢。