initphp/fiber-loops
Composer 安装命令:
composer require initphp/fiber-loops
包简介
A minimal cooperative task scheduler (event loop) for PHP, built on native fibers.
关键字:
README 文档
README
A minimal cooperative task scheduler for PHP, built on native fibers. Run several tasks on a single thread, hand control back and forth at points you choose, and wait for sub-tasks to finish — in a few dozen lines of dependency-free code.
What it is (and is not)
FiberLoops is a tiny scheduler. You queue tasks with defer() and drive them
with run(). Each task is a fiber; the loop advances the tasks round-robin,
running each one until it cooperatively yields (next() / sleep()) or
returns.
Scheduling is cooperative, not preemptive: nothing interrupts a task. A task
keeps the CPU until it yields or finishes, so long-running tasks must call
next() periodically to let their siblings make progress. There is no I/O
reactor, no stream/timer polling, no threads — it is a scheduling primitive you
can build those things on top of, not a full async runtime like ReactPHP or Amp.
Requirements
- PHP 8.1+ (fibers are a core language feature since 8.1 — no extension needed)
Installation
composer require initphp/fiber-loops
Quick start
require_once 'vendor/autoload.php'; use InitPHP\FiberLoops\Loop; $loop = new Loop(); $loop->defer(function () use ($loop) { foreach (['a', 'b', 'c'] as $step) { echo "task-1: $step\n"; $loop->next(); // yield: let other tasks run } }); $loop->defer(function () use ($loop) { foreach (['x', 'y', 'z'] as $step) { echo "task-2: $step\n"; $loop->next(); } }); $loop->run(); // drive every task to completion
task-1: a
task-2: x
task-1: b
task-2: y
task-1: c
task-2: z
The two tasks interleave because each one yields with next() after every step.
Remove the next() calls and the first task would run to completion before the
second one started.
The API
Loop implements InitPHP\FiberLoops\LoopInterface. Depend on the interface when
you want to substitute or mock the scheduler.
| Method | Description |
|---|---|
defer(callable|Fiber $task): void |
Queue a task. A callable is wrapped in a fiber. Safe to call during run(). |
run(): void |
Run every queued task to completion (blocks until the queue is empty). |
next(mixed $value = null): mixed |
Yield from the current task back to the scheduler. Must run inside a fiber. |
sleep(int|float $seconds): void |
Cooperatively pause the current task. Must run inside a fiber. |
await(callable|Fiber $task): mixed |
Run a task to completion and return its value, yielding while it works. |
defer() and run()
defer() queues work; run() executes it. A task added during run() (from
inside another task) is picked up on the next scheduling pass, so tasks can spawn
more tasks.
next()
next() is the yield point. Calling it suspends the current task and lets the
scheduler advance the others; the task resumes where it left off on the next pass.
It must be called from within a fiber (i.e. inside a deferred or awaited task) —
calling it from the main script throws a LoopException:
$loop->next(); // LoopException: Loop::next() must be called from within a fiber...
The bundled scheduler resumes tasks without a value, so
next()returnsnullunderrun()andawait(). The$valueargument is reserved for custom drivers and is ignored here.
sleep()
sleep() pauses the current task for at least the given number of seconds while
letting sibling tasks keep running:
$loop = new Loop(); $loop->defer(function () use ($loop) { $loop->sleep(0.2); // yields repeatedly for ~200ms foreach (range(0, 5) as $value) { echo $value . PHP_EOL; } }); $loop->defer(function () use ($loop) { foreach (range(6, 9) as $value) { echo $value . PHP_EOL; } }); $loop->run();
6
7
8
9
0
1
2
3
4
5
The second task finishes first because the first one is sleeping. sleep() is a
busy-wait that yields on every iteration: siblings progress, but the loop
does not idle the CPU. sleep(0) (or any non-positive value) returns immediately
without yielding. See docs/caveats.md for the implications.
await()
await() runs a task to completion and returns its value. From the main script
it drives the task synchronously:
$loop = new Loop(); $user = $loop->await(function () use ($loop) { $loop->next(); // may yield while doing work return ['id' => 42, 'name' => 'Ada']; }); echo "user: {$user['id']} / {$user['name']}\n"; // user: 42 / Ada
Called from inside a task, await() yields to the scheduler while the awaited
sub-task works, so other tasks keep running in the meantime:
$loop = new Loop(); $loop->defer(function () use ($loop) { echo "worker: awaiting a sub-task\n"; $sum = $loop->await(function () use ($loop) { $total = 0; foreach (range(1, 3) as $n) { $total += $n; $loop->next(); } return $total; }); echo "worker: sub-task returned $sum\n"; }); $loop->defer(function () use ($loop) { foreach (['tick', 'tick', 'tick'] as $t) { echo "heartbeat: $t\n"; $loop->next(); } }); $loop->run();
worker: awaiting a sub-task
heartbeat: tick
heartbeat: tick
heartbeat: tick
worker: sub-task returned 6
await() accepts a callable or a Fiber, started or not.
Error handling
next() and sleep() must be called from within a fiber. Doing otherwise throws
InitPHP\FiberLoops\Exception\LoopException (a RuntimeException) with an
actionable message, instead of PHP's bare FiberError.
Documentation
Full guides live in docs/:
| Guide | What it covers |
|---|---|
| Getting started | Install, your first two tasks, how the loop runs them. |
| Concepts | The scheduling model: fibers, the round-robin queue, cooperative yielding. |
| API reference | Every method, its signature, behaviour and edge cases. |
| await & concurrency | Awaiting sub-tasks from the main context and from inside a task. |
| Caveats & gotchas | Busy-wait sleep(), in-fiber preconditions, non-preemptive scheduling. |
Testing
composer install composer test # PHPUnit composer ci # cs-check + phpstan + tests
Contributing
Contributions are welcome. Please read the org-wide Contributing guide and the Security policy. Fork, branch, add tests for your change, and open a pull request.
Credits
License
Copyright © 2022 InitPHP — released under the MIT License.
initphp/fiber-loops 适用场景与选型建议
initphp/fiber-loops 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 11 次下载、GitHub Stars 达 6, 最近一次更新时间为 2022 年 07 月 12 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「event-loop」 「async」 「scheduler」 「loop」 「concurrency」 「coroutine」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 initphp/fiber-loops 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 initphp/fiber-loops 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 initphp/fiber-loops 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Symfony bundle to monitor and execute commands
The bundle for easy using json-rpc api on your project
Wrapper around proc_open to ease communication via streams between processes
An async event for hyperf.
An asynchronous event driven PHP framework for easily building fast, scalable network applications.
Swoole server process management
统计信息
- 总下载量: 11
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 6
- 点击次数: 27
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2022-07-12
