进化模拟 - 定时器事件处理的持久线程

时间:2013-10-12 16:00:44

标签: java multithreading timer evolutionary-algorithm

我正在研究一种简单的进化算法。

工作原理:

我有一个网格地图,每个细胞都是空白,植物或草食动物。 植物和食草动物是生物(植物不是,无论如何),所以它们都有能量和颜色。生物每隔几毫秒(当计时器触发时)就会发生任何事情。植物不断补充能量,食草动物失去能量。如果植物完全充电,它会以随机方向(北,南,东或西)观察,如果该方向的相邻细胞是空白,植物将再生成该细胞。草食动物通过食用植物恢复能量。当草食动物轮到做东西时,它会看着一个随机相邻的细胞。如果它是空的,食草动物就会移动到那里。如果它是一种植物,草食动物会尝试吃它然后移动到那里。食草动物的颜色越接近植物',草食动物成功的机会就越大。如果食草动物达到0能量,它就会死亡。如果食草动物达到最大能量,它也会繁殖。后代的颜色总是与父母的颜色略有不同。

这是一张图片:

enter image description here

这是从内部吃掉的很多植物。

过了一会儿,系统正常化了:

enter image description here

大片会消失,并且随时会出现几种颜色。当然,这是预期的。

所以,我现在有一个工作程序。但是,它由一个线程运行,我想让它多线程。我打算为地图上的每个单元格创建一个线程。

我知道这有点矫枉过正,但无论如何我都想这样做。这样,我可以拥有这些小的原子碎片,细胞,所有这些都可以异步工作,它们可以在飞行中互相插入,就好像把拼图拼凑起来一样。

这就是基本的想法。我想让细胞尽可能自主。我试图实现这个:我为每个单元格创建了一个swing计时器,当计时器触发时,我启动了一个线程让单元格进行操作。我还为每个单元格添加了锁定,这样shtuff就不会搞砸了。多个邻居尝试访问同一个小区。这个问题是每次单元格尝试执行某些操作时都会调用一个新线程。我知道这是非常消耗资源(第一手经验)所以我想以某种方式为每个单元格创建持久线程。每个线程都会处理它自己的单元的计时器,动作监听器,并在计时器触发时运行它的单元格的动作。这些线程基本上永远不会停止。我需要帮助,因为我不确定如何实现这样的系统。

编辑:澄清问题:我需要一个侦听计时器事件的线程示例,并在计时器触发时运行。这应该都发生在线程内。

4 个答案:

答案 0 :(得分:2)

我认为增加Thread的数量只有在增加cpu核心时才有意义。您可以考虑使用超线程。因此,例如,如果你有一个启用了HT的四核CPU,那么它可以同时处理8 Thread个。

另一件事是,这通常是以另一种方式完成的。假设你有10个物体(植物,食草动物,等等)。每个都有calculateNextState()之类的方法。您只需计算10个对象的循环中的所有状态,然后当您为所有状态创建新状态时,您将刷新GUI。你无限制地做这个广告。您不需要计时器,只需要考虑计算所需的时间。

示例:

你有一种食草动物,其速度为10个单位(x轴)。其位置为(2,4)上次计算与now()之间经过的时间为 200ms 您将其位置更新为(4,4)。等等...

至于并行化:您可以创建ThreadPool并将Runnable推入其中。事实上,每个Runnable都是计算GameObject的下一个状态的函数(我刚刚给出了你所拥有的生物的名字)。当所有ThreadPool完成工作后,您可以更新GUI。

主要的是:如果您为计算设置固定时间,则无法真正更新gui上的任意数量的对象,因为它可能需要比您设置的时间更长。< / p>

示例:如果您说“我想每秒更新一次”,但您有5.000.000个对象,则计算可能需要2秒。这就是为什么我建议你应该使用我描述的模型。所有状态计算都应该是可并行化的,因此您可以在线程之间分配工作。

然而,有一点需要注意:你必须考虑到2种不同的植物/食草动物试图扩展到上一次计算后空的同一个细胞的情况。

答案 1 :(得分:1)

不妨写下我自己的答案。

首先:您将无法使用纯实体线程,基于计时器的方法准确地表示您的模拟世界。

原因如下:

world model vs CPU model

当然,左侧是世界模型和右侧,是基于您的方法实现的简单线程模型。

现在,要指出的重点是:

    模拟模型中的
    1. 每个实体的状态完全内化。草食动物,植物等包含它本身需要的所有信息。
    2. 所有实体都是自主。实体不关心其他东西是否正在移动,被吃掉等,或者其他实体同时在做多少
    3. 所有实体均以实时运作。它们如何根据其内部状态出现,就是它们在世界上的表现。
  • 在实际实施模型中:
    1. 主内存中有全局状态。所有实体都需要将线程本地状态与全局状态同步,否则会遇到不一致。
      • 实体线程争夺有限的CPU资源。线程可以随时进入非活动状态 - 甚至不是“你的”线程来启动! 正在执行多少个其他线程变得非常相关。
      • 实体线程竞争主内存访问。当一个线程锁定一个公共锁时,另一个线程必须等到它被解锁。
    2. 实体线程完全脱离它们出现的方式(即在GUI查看器中)。

从这三点来看,我希望很明显模型是不兼容的。

你可能尝试使你的世界模型适应线程模型,但是你会遇到改变你的世界以适应实现的问题。例如,您提到的锁定 - 它们会改变您的世界的运作方式,具体取决于您的方法。

当然,如果在特定情况对此没问题,请继续(这意味着您对速度减少,通常伴随着大量的线程,以及同步带来的所有好问题)。

但是,在一般情况下,您应该根据您的规范选择实施,而不是相反。

如果你注意上述内容,你有很多选择,其中大部分都依赖于Adam Arold所描述的离散模拟步骤,并由clwhisk进行了细化。这些模型包括:

  • 使用ThreadPoolExecutorForkJoinPool处理工作单位的有限数量的工作线程,
  • 将网格模型编码为一组方程,
  • 等。等

答案 2 :(得分:0)

您没有定义持久性线程对您来说意味着什么。

在当前的计算机和操作系统上,{p> Threadsprocesses不一样persistent(请参阅application checkpointing)。例如,它们在单词的Java serializable中不是sense

您需要实现自己的计算持久性实现(而不是线程)。在continuation passing style中设计您的计划可能会有所帮助。拥有自己的持久计算概念(例如,让每个线程运行一个小循环,其状态是持久的和可序列化的。)

不要想到有数千(甚至数百)个线程;它们是昂贵的资源。考虑使用一个小thread pool(最多几十个线程)。线程池的大小应该是可配置的,不应该取决于数据的大小(或者你正在计算的问题)。

您可能需要考虑futures and promises,例如Java futures(在小型线程池中共享线程)。

答案 3 :(得分:0)

正如亚当的回答所暗示的那样,这通常是通过时间步长完成的。每个生物都有倒计时到下一个动作,并且最简单的形式是倒计时将是一个递减的整数,calculateNextState()在每一步都调用一切。但是你有更多的灵活性。例如,将生物存储在按(双)倒计时排序的优先级队列中。您可以通过在队列中混洗他们的顺序来随机打破关系,或者在倒计时中添加随机元素。最重要的是,您可以使用常规方法完全控制模拟。线程不是工作的工具 - 它们听起来像是做了额外的工作,每次有并行任务时都应该使用它,但事实并非如此。