vennv/vapm-pmmp

2.5.6 2024-09-02 05:40 UTC

README

  • 这是为 PocketMine-PMMP 设计的 Virion Async/Promise/Coroutine/Thread/GreenThread

Composer

composer require vennv/vapm-pmmp

如何设置?

  • 在此处官方下载 Phar:点击此处
  • 将它们下载并放入您的 Virion 文件夹中。如果您不明白 Virion 是什么,请点击此处
  • 要实现和使用方法,您必须首先在插件 onEnable 函数的顶部使用此库的方法
  • 示例
protected function onEnable() : void
{
    VapmPMMP::init($this);
}
  • 什么是 VapmPMMP::init($this) ?
/**
* @param PluginBase $plugin
*
* This method is called by VapmPMMP::init(), it will run event loop.
*/
public static function init(PluginBase $plugin) : void;

LibVapmPMMP 与 Await-Generator 的比较

  • 为什么处理大型系统? Vapm 使用基于 tick 的执行的任务调度器,而 Await-Generator 使用队列并在作用域内即时执行。比较这两种异步模型,一种使用队列存储并在特定作用域内即时执行,另一种将任务保存到任务调度器以进行 tick 执行,应基于以下因素
    1. 性能和灵活性
      • 在作用域内即时排队和执行: 由于任务在队列中出现时立即执行,因此此模型通常在处理方面更快。然而,如果同时出现太多任务,可能会导致过载,因为它们都在同一时间进行处理。
      • 基于 tick 的任务调度器: 使用任务调度器可以通过在 tick 中执行任务来控制任务的处理速度。这有助于避免过载并允许更流畅的系统资源分配。但是,如果 tick 设置了较长的间隔,则执行可能会变慢。
    2. 资源控制
      • 排队和即时执行: 如果需要立即处理大量任务,则可能会消耗更多资源,从而导致资源耗尽或系统延迟增加的风险。
      • 任务调度器: 通过在每个 tick 中仅执行有限数量的任务来帮助您更好地管理和控制资源,从而减轻系统压力。
    3. 实时响应
      • 排队和即时执行: 如果需要实时反馈,则任务即时处理更好。
      • 任务调度器: 由于任务必须等待下一个 tick 才能被处理,因此可能不适合需要即时响应的应用程序。
    4. 复杂性和维护
      • 排队和即时执行: 通常部署起来更简单,但如果系统高度复杂,则难以管理。
      • 任务调度器: 虽然更复杂,但长期来看提供了更多灵活性和易于维护。
    5. 用例
      • 排队和即时执行: 适用于需要立即处理且不涉及太多并发任务的应用程序。
      • 任务调度器: 适用于更复杂的系统,有时需要控制任务的处理,以确保稳定的性能。
  • 那么,您是否有办法将 Vapm 作为等待生成器使用? 您可以通过运行 CoroutineGen::runBlocking()AwaitGroup 等方法来实现,这些方法在 Vapm 中或更多其他地方可用。
  • 在任务调度器上处理此类异步任务是否可以? 这是完全可以的,因为任务调度器只能处理最多 20 个异步任务和 +1 个计划中的 CoroutineGens。(请注意,这里的处理意味着它将只处理每个任务一次,如果未完成,则跳过并在下一次处理!)
  • 为什么可以这样做? 当您知道它们在您认为任务非常繁重的地方等待时,这确实非常稳定!例如:点击 如您所见,我在那一刻停下来等待任务完成,而 Tick-Scheduler 会重复并再次处理。这使得在另一个 tick 中可以同时处理许多其他任务。
  • 等待生成器问题: Await-Generator 存在一个问题,即如果我创建一个承诺并要求它在声明后立即运行,而不等待,就像有一个用于数十亿个数字的 for 循环一样,如果我等待并在下面运行承诺,它将告诉我我在同步?我注意到库的 Await 处理类中有一个队列,然而,假设如果没有承诺被触发,需要满足的承诺是在它们被处理时?它们何时是实时的?如果我想处理 10 亿个任务并立即在完成后完成一些参数来做下一件事怎么办?请注意,这是 10 亿。
  • Await-Generator
$channel = new Channel;
Await::f2c(function() use ($channel) {
    for ($i = 0; $i < 5000000; $i++) {
        yield from $channel->sendAndWait($i);
    }
});
  • Vapm
/**
 * @throws Throwable
 */
public function loadWorlds(): Channel
{
    $channel = new Channel();
    CoroutineGen::runNonBlocking(function () use (&$channel): Generator {
        $i = 0;
        foreach (scandir($this->plugin->getServer()->getDataPath() . "worlds") as $world) {
            if ($world === "." || $world === "..") continue;
            if ($this->plugin->getManager()->isIslandNether($world)) {
                $i++;
                yield from $channel->sendGen($i);
                $this->applyIslandNether($world);
            } elseif ($this->plugin->getManager()->isIslandEnd($world)) {
                $i++;
                yield from $channel->sendGen($i);
                $this->applyIslandEnd($world);
            } else {
                $this->applyIslandOverworld($world);
            }
        }
        return $i;
    });
    return $channel;
}

// Process with Task by PMMP
// Load worlds
if (
    self::$doneLoadWorlds === null &&
    (microtime(true) - self::$lastTimeLoadWorlds) >= 5.0
) {
    self::$lastTimeLoadWorlds = microtime(true);
    self::$doneLoadWorlds = $this->plugin->getWorldManager()->loadWorlds();
} elseif (self::$doneLoadWorlds !== null) {
    CoroutineGen::runNonBlocking(function (): Generator {
        yield from self::$doneLoadWorlds->receiveGen(fn() => null);
        self::$doneLoadWorlds = null;
    });
}
// Completely waits and processes each slow incoming content that Channel sends without over-load the server when too many things are sent and received at once.

问题出现了,为什么我必须等待这么长时间来处理这种大的分歧,而不是异步快速和缓慢地通过 ticks 来处理?

  • 速度测试: 代码 根据固有方法,Await-Generator 仍然想要像往常一样等待和处理,而不使用任务调度器。 image