--- layout: docs title: Event Loop permalink: /event-loop/ --- It may surprise people to learn that the PHP standard library already has everything we need to write event-driven and non-blocking applications. We only reach the limits of native PHP's functionality in this area when we ask it to poll thousands of file descriptors for IO activity at the same time. Even in this case, though, the fault is not with PHP but the underlying system `select()` call which is linear in its performance degradation as load increases. For performance that scales out to high volume we require more advanced capabilities currently found only in extensions. If you wish to, for example, service 10,000 simultaneous clients in an Amp-backed socket server, you should use one of the event loop implementations based on a PHP extension. However, if you're using Amp in a strictly local program for non-blocking concurrency or you don't need to handle more than a few hundred simultaneous clients in a server application the native PHP functionality should be adequate. ## Global Accessor Amp uses a global accessor for the event loop as there's only one event loop for each application. It doesn't make sense to have two loops running at the same time, as they would just have to schedule each other in a busy waiting manner to operate correctly. The event loop should be accessed through the methods provided by `Amp\Loop`. On the first use of the accessor, Amp will automatically setup the best available driver, see next section. `Amp\Loop::set()` can be used to set a custom driver or to reset the driver in tests, as each test should run with a fresh driver instance to achieve test isolation. In case of PHPUnit, you can use a [`TestListener` to reset the event loop](https://github.com/amphp/phpunit-util) automatically after each tests. ## Implementations Amp offers different event loop implementations based on various backends. All implementations extend `Amp\Loop\Driver`. Each behaves exactly the same way from an external API perspective. The main differences have to do with underlying performance characteristics. The current implementations are listed here: | Class | Extension | Repository | | ------------------------- | ------------------------------------------------------ | ---------- | | `Amp\Loop\NativeDriver` | – | - | | `Amp\Loop\EvDriver` | [`pecl/ev`](https://pecl.php.net/package/ev) | [`php-ev`](https://bitbucket.org/osmanov/pecl-ev) | | `Amp\Loop\EventDriver` | [`pecl/event`](https://pecl.php.net/package/event) | [`pecl-event`](https://bitbucket.org/osmanov/pecl-event) | | `Amp\Loop\UvDriver` | [`pecl/uv`](https://pecl.php.net/package/uv) | [`php-uv`](https://github.com/bwoebi/php-uv) | It's not important to choose one implementation for your application. Amp will automatically select the best available driver. It's perfectly fine to have one of the extensions in production while relying on the `NativeDriver` locally for development. If you want to quickly switch implementations during development, e.g. for comparison or testing, you can set the `AMP_LOOP_DRIVER` environment variable to one of the classes. If you use a custom implementation, this only works if the implementation doesn't take any arguments. ## Event Loop as Task Scheduler The first thing we need to understand to program effectively using an event loop is this: **The event loop is our task scheduler.** The event loop controls the program flow as long as it runs. Once we tell the event loop to run it will maintain control until the application errors out, has nothing left to do, or is explicitly stopped. Consider this very simple example: ```php