Multithreading 如何实现多线程

Multithreading 如何实现多线程,multithreading,clojure,Multithreading,Clojure,游戏规则 考虑一个简单的两人游戏,如下所示:偶数个硬币排成一行。每名玩家轮流取出一行一端的硬币。目标是在所有硬币都被拿走后,拥有最高的硬币价值 玩家一找到所有偶数硬币和所有奇数硬币的总和。如果奇数硬币的总和更高,玩家一将获得最左边的硬币;否则,他会选择最右边的 玩家二有选择权,硬币数量为奇数。所以他试着从两端取一枚硬币,看看哪个选项会让玩家1的处境更糟 问题 我基本上想实现这个程序。我对Clojure还很陌生,我在网上找不到任何关于多线程的好材料,可以应用到我的程序中 代码 (ns game.c

游戏规则

考虑一个简单的两人游戏,如下所示:偶数个硬币排成一行。每名玩家轮流取出一行一端的硬币。目标是在所有硬币都被拿走后,拥有最高的硬币价值

玩家一找到所有偶数硬币和所有奇数硬币的总和。如果奇数硬币的总和更高,玩家一将获得最左边的硬币;否则,他会选择最右边的

玩家二有选择权,硬币数量为奇数。所以他试着从两端取一枚硬币,看看哪个选项会让玩家1的处境更糟

问题

我基本上想实现这个程序。我对Clojure还很陌生,我在网上找不到任何关于多线程的好材料,可以应用到我的程序中

代码

(ns game.core
  (:gen-class))

(defn vector-from-string [s]
  (drop 1 (map read-string (clojure.string/split (clojure.string/trim-newline s) #" "))))

(defn string-from-file [f]
  (slurp f))

(defn sum-of-evens [v]
  (def evens (vector))
  (loop [v v, index 1]
    (when (seq v)
      (if (even? index)
        (def evens (conj evens (first v))))
      (recur (rest v) (inc index))))
  (reduce + evens))

(defn sum-of-odds [v]
  (def odds (vector))
  (loop [v v, index 1]
    (when (seq v)
      (if (odd? index)
        (def odds (conj odds (first v))))
      (recur (rest v) (inc index))))
  (reduce + odds))

(defn player-two [v p1score p2score]
  (if (not (empty? v))
    (if (> (max (sum-of-odds (drop 1 v)) (sum-of-evens (drop 1 v))) (max (sum-of-odds (drop-last v)) (sum-of-evens (drop-last v))))
      (player-one (drop-last v) p1score (+ p2score(last v)))
      (player-one (drop 1 v) p1score (+ p2score (first v))))
    (println "p1score" p1score "p2score" p2score)))

(defn player-one [v p1score p2score]
  (if (not (empty? v))
    (if (> (sum-of-odds v) (sum-of-evens v))
      (player-two (drop 1 v) (+ p1score (first v)) p2score)
      (player-two (drop-last v) (+ p1score (last v)) p2score))
    (println "p1score" p1score "p2score" p2score)))

(defn -main [& args]
  (let [v (vector-from-string (string-from-file "numbers.txt")) ]
    (player-one v 0 0)))

因此,
-main
首先运行
player one
函数,
player one
调用
player two
,它们都会继续运行,直到程序结束。我想以某种方式实现多线程,以加快这个游戏的执行速度,同时增加启动硬币的数量。

您的代码目前非常不规范

以下几句话有望帮助您进入正确的方向:

def
内部的
def
(或
def
)几乎总是错误的。你在考虑变量赋值和可变变量。这不是Clojure的工作方式。如果绝对必须,请在递归中使用变量(也几乎总是错误的,但比
def
内部
defn
的错误要少)

你的循环太复杂了。是否要对元素按偶数或奇数索引求和?结合使用
reduce
take nth
rest

(take-nth 2 [1 2 3])
;=> (1 3)
(take-nth 2 (rest [1 2 3 4]))
;=> (2 4)
整个过程看起来就像是一遍又一遍地编译它,然后用它运行JVM。我说得对吗?首选的方法是在REPL工作。如何访问它,取决于您使用的编辑环境。有很多初学者友好的回复。大猩猩REPL就是一个例子

一旦您的代码和开发工作流程处于更好的状态,您可能希望探索类似于
pmap
future
的功能,以便轻松访问多线程。更高级的东西包括一个名为
core.async
的库,但对于初学者来说,这可能不是理想的途径。您还可以使用Java互操作来创建线程。同样地,这虽然不是很难做到,但需要一点Clojure的经验


希望这会有所帮助,即使这不是对您问题的直接回答。

首先让我们看看您的示例中的一些问题,这些问题在并行化此代码之前需要解决

evens之和
在函数中使用
def
,这几乎总是一个错误。这似乎有你想要的效果,但这不是实现它的正确方法
def
s通常用于名称空间级别(与函数
defn
s处于同一级别)的值。通过
def
,我们可以重构
evens之和
,以避免无意中依赖副作用行为:

(defn sum-of-evens [v]
  (loop [v v
         index 1
         evens []]
    (if (seq v)
      (recur (rest v)
             (inc index)
             (if (even? index) ;; add a binding to loop, not a def
               (conj evens (first v))
               evens))         ;; pass unchanged value when necessary
      (reduce + evens))))
但我们可以通过
保持索引
进一步简化此函数:

(defn sum-of-evens [coll]
  (->> coll
       (keep-indexed (fn [i v] (when (even? (inc i))
                                 v)))
       (apply +)))
当我们对
赔率之和做同样的处理时,我们可以看到函数几乎是相同的,除了它们使用的条件:
奇数?
偶数?
。我们可以制作另一个采用谓词函数的函数:

(defn sum-by-index-pred [f coll]
  (->> coll
       (keep-indexed (fn [i v] (when (f i) v)))
       (apply +)))
;; using partial application and function composition
(def sum-of-evens (partial sum-by-index-pred (comp even? inc)))
(def sum-of-odds (partial sum-by-index-pred (comp odd? inc)))
查看
player one
player two
的实现,它们似乎是相互递归的。我不明白你怎么能把它并行化,使它更快,因为每个回合都取决于前一回合的结果;没有什么可以并行化的

我建议对此进行重构,以便在一个位置计算游戏规则和状态,而不是相互递归函数

(loop [scores (array-map :player-1 0 :player-2 0)
       turns (cycle (keys scores))
       vs (shuffle (range 100))]
  (if (seq vs)
    (let [higher-odds? (> (sum-of-odds vs) (sum-of-evens vs))
          scores (if higher-odds?
                   (update scores (first turns) + (first vs))
                   (update scores (first turns) + (last vs)))
          remain (if higher-odds?
                   (rest vs)
                   (butlast vs))]
      (recur scores (rest turns) remain))
    (prn scores)))
;; {:player-1 2624, :player-2 2326}

我不确定这是否保留了您最初的游戏逻辑,但它应该很接近,并且它确实为两个以上的玩家推广了它。尝试将
:player-3 0
添加到开始的
分数中

不仅是在函数内部使用
def
是不规则的,而且更改名称空间级别的变量绑定将使多线程处理此代码变得非常困难。多谢您在我的代码中提供的重构帮助。
赔率之和
偶数之和
函数现在更加优雅了。我使用的是repl,特别是lein repl。该线程的另一位回答者提到,我无法探索多线程,因为我的两个函数
playerone
playertwo
是相互递归的。你同意他的观点吗?如果没有,我怎么能在我的程序中实现多线程呢?泰勒在重构你的函数方面做得非常好。你一定要按照他的思路去做。我也喜欢他在《循环》中使用懒惰。确保你也明白这一点。是的,交互递归是针对多线程的。问问你自己,你想用线程做什么模型,为什么。如果玩家应该是线程,你需要一些机制来协调他们轮流。我建议您在使用Clojure原语构建多线程应用程序之前,先深入了解Clojure知识和方法。干杯,你写的最后一段代码。。。我不知道它在干什么。但是当我用参数
v
将它包装在函数中,并用
v
替换
vs
的所有实例(第一个除外)时,我知道它不起作用。