草庐IT

javascript - 在Screeps中,是否以允许写入CPU极限健壮代码的方式实现CPU极限?

coder 2024-07-19 原文

在Screeps中,每个玩家对CPU的使用都受到限制,但是documentation for this feature并没有使执行此方法的方式足够清晰,无法编写CPU限制健壮的代码。我考虑了以下四种可能性:

1.玩家的循环永远不会中断。

在一种极端情况下,玩家的内存反序列化,主脚本执行和内存重新序列化永远不会中断,并且超过CPU限制仅意味着玩家的周期将在随后的滴答声中跳过,直到偿还CPU债务为止。在这种情况下,CPU限制健壮的代码并不是绝对必要的,但它对于检测何时跳过播放器的周期并可能更有效地开始工作仍然很有用。可以使用以下代码轻松实现:

module.exports.loop = function()
{
  var skippedTicks = 0;

  if ( 'time' in Memory )
  {
    skippedTicks = Game.time - Memory.time - 1;
  }

  // Main body of loop goes here, and possibly uses skippedTicks to try to do
  // things more efficiently.

  Memory.time = Game.time;
};

这种管理玩家的CPU使用率的方法很容易受到无限循环的滥用,我几乎可以肯定这不是Screeps的行为。

2.玩家的周期是原子的。

下一个可能性是玩家的循环是原子的。如果超过了CPU限制,则会中断玩家的循环,但是既定的游戏状态不会更改,也不会提交对内存的更改。当检测到中断的周期时,提高效率变得更加重要,因为忽略它意味着玩家的脚本将无法更改游戏状态或内存。但是,检测中断的循环仍然很简单:
module.exports.loop = function()
{
  var failedTicks = 0;

  if ( 'time' in Memory )
  {
    failedTicks = Game.time - Memory.time - 1;

    // N failed ticks means the result of this calculation failed to commit N times.
    Memory.workQuota /= Math.pow( 2, failedTicks );
  }

  // Main body of loop goes here, and uses Memory.workQuota to limit the number
  // of active game objects to process.

  Memory.time = Game.time;
}

2.5。对内存的更改是原子的,但对游戏对象的更改不是。

编辑:这种可能性发生在我阅读了RawMemory对象的文档后。如果脚本被中断,则任何已安排的游戏状态更改都将被提交,但对内存的任何更改都不会被提交。考虑到RawMemory提供的功能,这是有道理的,因为如果脚本在运行自定义内存序列化之前被中断,则会运行默认的JSON序列化,这会使自定义内存序列化更加复杂:自定义反序列化将需要能够处理默认JSON以及自定义序列化编写的任何格式。

3. JavaScript语句是原子的。

另一种可能性是,播放器的循环不是原子的,而是JavaScript语句。当玩家的周期因超出CPU限制而中断时,不完整的游戏状态更改和内存更改将被提交,但是要进行仔细的编码-进行Screeps API调用的语句必须将调用结果分配给Memory键-游戏状态更改和内存更改不会相互矛盾。在这种情况下,编写完全CPU限制的健壮代码似乎很复杂-这不是我尚未解决的问题,并且在尝试之前,请确保这是Screeps的真实行为。

4.没有什么是原子的。

在另一种极端情况下,甚至没有单个语句是原子的:将Screeps API调用的结果分配给Memory中的键的语句可能在调用完成和结果分配之间被中断,并且不完整的游戏状态都会改变并提交了不完整的内存更改(现在彼此不一致)。在这种情况下,编写CPU限制健壮代码的可能性非常有限。例如,尽管通过以下语句写入到Memory的值的存在无疑表明Screeps API调用已完成,但毫无疑问并不表明该调用未完成:
Memory.callResults[ Game.time ][ creep.name ] = creep.move( TOP );

有谁知道这是蠕动的行为吗?还是我没有考虑过的其他东西?文档中的以下引用:

The CPU limit 100 means that after 100 ms execution of your script will be terminated even if it has not accomplished some work yet.



暗示可能是情况3或情况4,但不是很令人信服。

另一方面,在模拟模式下使用单个蠕变,以下主循环并在对话框中为无响应脚本选择“终止”的实验结果:
module.exports.loop = function()
{
  var failedTicks = 0;

  if ( 'time' in Memory )
  {
    var failedTicks = Game.time - Memory.time - 1;

    console.log( '' + failedTicks + ' failed ticks.' );
  }

  for ( var creepName in Game.creeps )
  {
    var creep = Game.creeps[ creepName ];

    creep.move( TOP );
  }

  if ( failedTicks < 3 )
  {
    // This intentional infinite loop was initially commented out, and
    // uncommented after Memory.time had been successfully initialized.

    while ( true )
    {
    }
  }

  Memory.time = Game.time;
};

是蠕变仅在跳动无限循环的跳动处移动,因为failTicks达到了其阈值。这指向情况2,但不是确定性的,因为仿真模式下的CPU限制不同于在线限制-除非使用对话框的“终止”按钮终止,否则它似乎是无限的。

最佳答案

它不是#1或#2。我敢打赌,它是#4,最有意义的是监视主循环外部的CPU使用率,并在达到限制时将其杀死。 #3将需要screeps服务器中的复杂代码来执行“语句级”事务。正如您所发现的,模拟器中没有CPU限制。

大多数玩家通过简单地将关键代码放在主循环的早期来解决此问题,例如塔代码首先出现,然后是生成代码,然后是蠕变运动/工作。这也可以防止代码中未捕获的异常,因为最关键的功能(希望)已经执行。但是,这对于解决CPU限制是一个糟糕的解决方案,在我看来,一旦您用完存储桶中的所有CPU并不断达到常规限制,就好像您的代码每第二个跳动就会跳过一次。

我现在没有CPU问题(已订阅),但是我可以通过在结尾处放置CPU密集型代码来解决此问题,如果可能的话,只有在您的存储桶中有足够的CPU且您只有在运行时才执行远远没有达到您的每点击500 CPU限制。它还有助于增大蠕变,这通常是寻路甚至是移动(每移动0.2)占用大量CPU的现象,而蠕变越大意味着蠕变越少。

关于javascript - 在Screeps中,是否以允许写入CPU极限健壮代码的方式实现CPU极限?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38943489/

有关javascript - 在Screeps中,是否以允许写入CPU极限健壮代码的方式实现CPU极限?的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  6. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  7. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  8. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  9. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  10. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

随机推荐