Download the PHP package symplely/coroutine without Composer
On this page you can find all versions of the php package symplely/coroutine. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download symplely/coroutine
More information about symplely/coroutine
Files in symplely/coroutine
Package coroutine
Short Description Cooperative multitasking using generators. The basics of coroutines, async and await!
License MIT
Homepage https://github.com/symplely/coroutine
Informations about the package coroutine
Coroutine
This is version 2x, it breaks version 1x, by namespace of global functions, moving all required CONSTANTS to the dependence package. This version includes the new Fiber implementation, with no need for PHP ext-fibers extension, slated for PHP 8.1. All ext-fibers
tests, and examples as they have them, has been implemented here in examples/fiber, tests/fiber and tests/FiberTest.php.
For maximum performance it's advisable to install the cross-platform libuv library, the PHP extension ext-uv. See the online book for a full tutorial overview of it's usage.
All libuv
socket/stream/udp/tcp
like features will need to reimplemented for Windows, the previous assumption they where broken, that is not the case, issue with PHPext-uv
version of libuv being used, and the assumption how the feature should work. As such current implementation using nativestream_select
for Windows, will be rework/refactored.This package next version after 2x release, will require uv-ffi an FFI version of
ext-uv
of libuv, as such no additional binary library package will need to be downloaded/installed, and some current dependencies will no longer be necessary.
For a fundamental conceptional overview read "Concurrency and PHP in relation to modern programming languages, Python, Go, NodeJS, Rust, Etc", currently in draft form, will be posted on dev.io when completed.
This version also implements PHP ext-parallel extension in a way that uses the child process features of libuv. For a quick performance study between a thread and process see Launching Linux threads and processes with clone.
The implement here follows parallel\Runtime,parallel\Future, parallel\Channel, and Functional API specs as defined, but without the many limitations.
The limitations are overcome by using opis/closure package. All ext-parallel extension tests and examples, have been mainly modified here in examples/parallel, tests/parallel to include this package library instead and remove single array parameter requirement to variadic array. The tests with a somewhat major difference have .1
added to filename, some test are skipped that might require yield
for proper usage.
The ext-parallel events
and sync
API are not implemented, don't see a use case and is already internally part of this coroutine package.
Table of Contents
- Introduction
- Functions
- Installation
- Usage
- Development
- Todo
- Credits/References
- Contributing
- License
Introduction
What is Async? Simply avoiding the blocking of the very next instruction. The mechanism of capturing and running later.
What issues the current PHP implementations this package address? Ease of use. ReactPHP both do and get you asynchronous results. But both require more setup by the user/developer to get a simple line of code to run. There is also Swoole and Hhvm, but neither are standard PHP installations.
When using Amp or ReactPHP and some of the packages based upon them, you must not only manage the Callbacks
you provided, but also the returned Promise
object, and the Event Loop
object. These libraries modeling themselves around old school Javascript, where Javascript
nowadays moving towards simple async/await
syntax. Which brings up this question.
What does ease of use
mean?
We can start by reviewing other programming languages implementations. And the fact you already have a working application, that you want various parts to run more responsive, which translates to do more.
Go has it's Goroutine keyword go
then your function and statements.
These links of Python, Ruby, Rust, Nim, C#, Elixir, Java, and C++ details keywords async/await
combined with a function and statements.
When using they return the actual results you want, no meddling with any objects, no callbacks, and upon calling everything to up that point continues to run.
The thing about each, is the history leading to the feature, the actual behavior, the underlying concepts are the same, and a simple calling structure statement. They all reference in various ways the use of yield
or iterators
, which this package relies upon and makes the following true.
The only thing you will do to make your code asynchronous
, is placing yield
within, and prefix calling your code with yield
to get actual results
you want.
With this package you will have a PHP version of async/await
, by just using yield
.
There are a few helper functions available to tie everything together. Mainly, away()
that's similar to Python's create_task(), that behaves like Google's go() keyword, which is included here as a alias function go()
.
By using, it immediately returns a number, that can be used with gather()
, another Python like function, which also behaves like Google's WaitGroup. This will wait and return the result of a code distant/detached for running in the background
.
This package follows a new paradigm Behavioral Programming with the concept of B-threads, functional generators.
The base overall usage of Swoole Coroutine, and FaceBook's Hhvm PHP follows the same outline implementations as others and put forth here.
To illustrate further take this comparison between NodeJS and Python from Intro to Async Concurrency in Python vs. Node.js.
Using this package as setout, it's the same simplicity:
Try recreating this with the other pure PHP async implementations, they would need an rewrite first to come close.
A Coroutine here are specially crafted functions that are based on generators, with the use of yield
and yield from
. When used, they control context, meaning capture/release
an application's execution flow.
When yield
is placed within an block of code, it indicates to the calling function, that an object will be returned instead, the code is not immediately executed.
This package represent that calling function, an scheduler, similar to an event loop. A coroutine needs to be scheduled to run, and once scheduled coroutines are wrapped in an Task
, which are a type of Promise.
A task
is an object that represents some work to be done, potentially with a result at the end of it. These tasks are registered with a scheduler that is responsible for running them.
Due to the single-threaded nature of PHP (without extensions anyway), we cannot think of a task
as doing a single long-running calculation - this will block the single thread until the task is finished.
Instead, tasks
must perform work in small chunks/iterations ('ticks') where possible, passing control back to the scheduler at appropriate points. This is known as cooperative multi-tasking (so called because the tasks must cooperate by yielding control voluntarily).
The scheduler is responsible for 'ticking' the scheduled tasks, with each scheduled task being repeatedly 'ticked' until it is complete. It is up to the scheduler implementation how to do this in a way that allows all scheduled tasks to run.
A task
can become complete in one of three ways:
When using this package, and the code you are working on contain yield
points, these define points is where a context switch can happen if other tasks are pending, but will not if no other task is pending. This can also be seen as breakpoints/traps, like when using an debugger, when triggered, the debugger steps in, an you can view state and step thought the remainder of your code.
A context switch represents the scheduler yielding the flow of control from one coroutine to the next.
A coroutine here is define as an function/method containing the
yield
keyword, in which will return generator object.
The generator object that's immediately returned, gives us access to few methods, that allow itself to progress.
So here we have a very special case with Generators
in that it being part of the PHP language, and when looked at through the lens of how Promise's work, and that's to not block, just execute line and return. The main idea of being asynchronous.
Promises returns an object, that's placed into an event loop queue. The event loop does the actual executing the callback attached to the object. This is really a manual process, with much code state/overhead to manage. This is called an Reactor pattern of execution, dispatches callbacks synchronously.
The mechanics of an event loop is already present when an a generator is put in motion. I see this as an Proactor pattern. Since the action of yield
ing is the initiator, begins the process of checking resource availability, performing operations/actions at that moment, and handling/returning completion events, all asynchronously.
Take a read of this post, What are coroutines in C++20?
This package performs cooperative scheduling, the basics for multitasking, asynchronous programming.
The steps, that's taking place when an yield
is introduced.
- The function is now an
coroutine
. - The object returned is captured by the
scheduler
. - The scheduler, wraps this captured
generator
object around antask
object. - The task object has additional methods and features, it could be seen as
promise
like. - The task is now place into an
task queue
controlled by thescheduler
. - You
run
yourfunction
, putting everything in motion. Here you are not starting any event loop. What could be seen as an event loop, is the work being done before or after thetask
is place into action by thescheduler
. - Where will this
task
land/return to? Answer: The same location that called it, there are no callbacks.
Step 1, is implemented in other languages with an specific keyword,
async
.Steps 2 to 6, is preformed in other languages with an specific keyword,
await
.
The terminology/naming used here is more in line with Python's Asyncio and Curio usage. In fact, most of the source code method calls has been change to match theres.
This package should be seen/used as an user-land extension, it's usage of yield
has been envisioned from RFC creators.
Functions
Only the functions located here and in the Core.php file should be used. Direct access to object class libraries is discouraged, the names might change, or altogether drop if not listed here. Third party library package development is the exception.
The functions for Network related in Stream.php, File System in Path.php, and Processes in Worker.php, all have been namespaced, so use as follows:
Installation
This version will use libuv features if available. Do one of the following to install.
For Debian like distributions, Ubuntu...
For RedHat like distributions, CentOS...
Now have Pecl auto compile, install, and setup.
For Windows there is good news, native async thru libuv
has arrived.
Windows builds for stable PHP versions are available from PECL.
Directly download latest from https://windows.php.net/downloads/pecl/releases/uv/0.2.4/
Extract libuv.dll
to sample directory as PHP
binary executable, and extract php_uv.dll
to ext\
directory.
Enable extension php_sockets.dll
and php_uv.dll
in php.ini
Note: Seems there are issues with PHP ZTS on both Windows and Linux when using
uv_spawn
.
Usage
In general, any method/function having the yield
keyword, will operate as an interruption point, suspend current routine, do something else, then return/resume.
There after, review as below, the scripts in the examples folder.
Development
Todo
- Add
WebSocket
support, or really convert/rewrite some package. - Add
Database
support, base off my maintenance of ezsql. - Add more standard examples from other languages, converted over.
- Update docs in reference to similar sections of functionally in Python, Go or any other languages.
Credits/References
Nikita Popov Cooperative multitasking using coroutines (in PHP!). Which this package forks Ditaio, restructuring/rewriting.
Parallel class is a restructured/rewrite of spatie/async. The Parallel class rely upon symplely/spawn as a dependency, used for subprocess management/execution, it uses uv_spawn
of libuv for launching processes. The Spawn package has opis/closure as an dependency, used to overcome PHP serialization limitations, and symfony/process as a fallback to proc_open
for launching processes, in case libuv the PHP-UV extension is not installed.
Contributing
Contributions are encouraged and welcome; I am always happy to get feedback or pull requests on Github :) Create Github Issues for bugs and new features and comment on the ones you are interested in.
License
The MIT License (MIT). Please see License File for more information.