1
0
mirror of https://github.com/danog/parallel.git synced 2024-11-26 12:24:40 +01:00

Apply Amp's code style

This commit is contained in:
Niklas Keller 2017-05-18 09:51:31 +02:00
parent 1f637cfc6f
commit 2e9a29ae1c
64 changed files with 357 additions and 224 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.php_cs.cache
.vagrant
build
composer.lock

40
.php_cs.dist Normal file
View File

@ -0,0 +1,40 @@
<?php
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules([
"@PSR1" => true,
"@PSR2" => true,
"braces" => [
"allow_single_line_closure" => true,
"position_after_functions_and_oop_constructs" => "same",
],
"array_syntax" => ["syntax" => "short"],
"cast_spaces" => true,
"combine_consecutive_unsets" => true,
"function_to_constant" => true,
"no_multiline_whitespace_before_semicolons" => true,
"no_unused_imports" => true,
"no_useless_else" => true,
"no_useless_return" => true,
"no_whitespace_before_comma_in_array" => true,
"no_whitespace_in_blank_line" => true,
"non_printable_character" => true,
"normalize_index_brace" => true,
"ordered_imports" => true,
"php_unit_construct" => true,
"php_unit_dedicate_assert" => true,
"php_unit_fqcn_annotation" => true,
"phpdoc_summary" => true,
"phpdoc_types" => true,
"psr4" => true,
"return_type_declaration" => ["space_before" => "none"],
"short_scalar_cast" => true,
"single_blank_line_before_namespace" => true,
])
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__ . "/example")
->in(__DIR__ . "/lib")
->in(__DIR__ . "/test")
);

45
Makefile Normal file
View File

@ -0,0 +1,45 @@
PHP_BIN := php
COMPOSER_BIN := composer
COVERAGE = coverage
SRCS = lib test
find_php_files = $(shell find $(1) -type f -name "*.php")
src = $(foreach d,$(SRCS),$(call find_php_files,$(d)))
.PHONY: test
test: setup phpunit code-style
.PHONY: clean
clean: clean-coverage clean-vendor
.PHONY: clean-coverage
clean-coverage:
test ! -e coverage || rm -r coverage
.PHONY: clean-vendor
clean-vendor:
test ! -e vendor || rm -r vendor
.PHONY: setup
setup: vendor/autoload.php
.PHONY: deps-update
deps-update:
$(COMPOSER_BIN) update
.PHONY: phpunit
phpunit: setup
$(PHP_BIN) vendor/bin/phpunit
.PHONY: code-style
code-style: setup
PHP_CS_FIXER_IGNORE_ENV=1 $(PHP_BIN) vendor/bin/php-cs-fixer --diff -v fix
composer.lock: composer.json
$(COMPOSER_BIN) install
touch $@
vendor/autoload.php: composer.lock
$(COMPOSER_BIN) install
touch $@

View File

@ -21,13 +21,14 @@
}
],
"require": {
"amphp/amp": "^2.0",
"amphp/amp": "^2",
"amphp/byte-stream": "dev-master as 0.1",
"amphp/process": "dev-amp_v2 as 0.2"
},
"require-dev": {
"amphp/phpunit-util": "dev-master",
"phpunit/phpunit": "^6.0"
"friendsofphp/php-cs-fixer": "^2.3",
"phpunit/phpunit": "^6"
},
"minimum-stability": "dev",
"suggest": {

View File

@ -1,7 +1,8 @@
<?php
namespace Amp\Parallel\Example;
use Amp\Parallel\Worker\{ Environment, Task };
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
class BlockingTask implements Task {
/**

View File

@ -2,8 +2,9 @@
<?php
require dirname(__DIR__).'/vendor/autoload.php';
use Amp\Loop;
use Amp\Parallel\Threading\Thread;
use Amp\{ Loop, Pause };
use Amp\Pause;
Loop::run(function () {
$timer = Loop::repeat(1000, function () {
@ -11,30 +12,30 @@ Loop::run(function () {
$i = $i ? ++$i : 1;
print "Demonstrating how alive the parent is for the {$i}th time.\n";
});
try {
// Create a new child thread that does some blocking stuff.
$context = Thread::spawn(function () {
printf("\$this: %s\n", get_class($this));
printf("Received the following from parent: %s\n", yield $this->receive());
print "Sleeping for 3 seconds...\n";
sleep(3); // Blocking call in thread.
yield $this->send("Data sent from child.");
print "Sleeping for 2 seconds...\n";
sleep(2); // Blocking call in thread.
return 42;
});
print "Waiting 2 seconds to send start data...\n";
yield new Pause(2000);
yield $context->send("Start data");
printf("Received the following from child: %s\n", yield $context->receive());
printf("Thread ended with value %d!\n", yield $context->join());
} finally {

View File

@ -2,15 +2,17 @@
<?php
require dirname(__DIR__).'/vendor/autoload.php';
use Amp\{ Coroutine, Loop };
use Amp\Parallel\{ Example\BlockingTask, Worker\DefaultPool };
use Amp\Coroutine;
use Amp\Loop;
use Amp\Parallel\Example\BlockingTask;
use Amp\Parallel\Worker\DefaultPool;
Loop::run(function() {
Loop::run(function () {
$timer = Loop::repeat(100, function () {
printf(".\n");
});
Loop::unreference($timer);
$pool = new DefaultPool;
$pool->start();
@ -33,7 +35,7 @@ Loop::run(function() {
$result = yield $pool->enqueue(new BlockingTask('file_get_contents', $url));
printf("Read from %s: %d bytes\n", $url, strlen($result));
};
$coroutines = array_map(function (callable $coroutine): Coroutine {
return new Coroutine($coroutine());
}, $coroutines);
@ -42,4 +44,3 @@ Loop::run(function() {
return yield $pool->shutdown();
});

View File

@ -2,8 +2,8 @@
<?php
require dirname(__DIR__).'/vendor/autoload.php';
use Amp\Parallel\Worker\DefaultWorkerFactory;
use Amp\Parallel\Example\BlockingTask;
use Amp\Parallel\Worker\DefaultWorkerFactory;
Amp\Loop::run(function () {
$factory = new DefaultWorkerFactory();

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel;
class ContextException extends \Exception {}
class ContextException extends \Exception {
}

View File

@ -2,10 +2,21 @@
namespace Amp\Parallel\Forking;
use Amp\{ Coroutine, Loop, Promise };
use Amp\Parallel\{ ContextException, Process, StatusError, Strand, SynchronizationError };
use Amp\Parallel\Sync\{ Channel, ChannelException, ChannelledSocket, SerializationException };
use Amp\Parallel\Sync\Internal\{ ExitFailure, ExitResult, ExitSuccess };
use Amp\Coroutine;
use Amp\Loop;
use Amp\Parallel\ContextException;
use Amp\Parallel\Process;
use Amp\Parallel\StatusError;
use Amp\Parallel\Strand;
use Amp\Parallel\Sync\Channel;
use Amp\Parallel\Sync\ChannelException;
use Amp\Parallel\Sync\ChannelledSocket;
use Amp\Parallel\Sync\Internal\ExitFailure;
use Amp\Parallel\Sync\Internal\ExitResult;
use Amp\Parallel\Sync\Internal\ExitSuccess;
use Amp\Parallel\Sync\SerializationException;
use Amp\Parallel\SynchronizationError;
use Amp\Promise;
use function Amp\call;
/**

View File

@ -5,7 +5,7 @@ namespace Amp\Parallel;
class PanicError extends \Error {
/** @var string Class name of uncaught exception. */
private $name;
/** @var string Stack trace of the panic. */
private $trace;
@ -22,7 +22,7 @@ class PanicError extends \Error {
$this->name = $name;
$this->trace = $trace;
}
/**
* Returns the class name of the uncaught exception.
*

View File

@ -2,17 +2,18 @@
namespace Amp\Parallel\Process;
use function Amp\call;
use Amp\{ Coroutine, Promise };
use Amp\Parallel\{
ContextException,
Process as ProcessContext,
StatusError,
Strand,
SynchronizationError
};
use Amp\Parallel\Sync\{ ChannelException, ChannelledSocket, Internal\ExitResult };
use Amp\Coroutine;
use Amp\Parallel\ContextException;
use Amp\Parallel\Process as ProcessContext;
use Amp\Parallel\StatusError;
use Amp\Parallel\Strand;
use Amp\Parallel\Sync\ChannelException;
use Amp\Parallel\Sync\ChannelledSocket;
use Amp\Parallel\Sync\Internal\ExitResult;
use Amp\Parallel\SynchronizationError;
use Amp\Process\Process;
use Amp\Promise;
use function Amp\call;
class ChannelledProcess implements ProcessContext, Strand {
/** @var \Amp\Process\Process */

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel;
class StatusError extends \Error {}
class StatusError extends \Error {
}

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel;
interface Strand extends Context, Sync\Channel {}
interface Strand extends Context, Sync\Channel {
}

View File

@ -2,35 +2,39 @@
namespace Amp\Parallel\Sync;
use Amp\{ Deferred, Failure, Loop, Promise, Success };
use Amp\Deferred;
use Amp\Failure;
use Amp\Loop;
use Amp\Promise;
use Amp\Success;
class ChannelledSocket implements Channel {
const HEADER_LENGTH = 5;
/** @var resource Stream resource. */
private $readResource;
/** @var resource Stream resource. */
private $writeResource;
/** @var string onReadable loop watcher. */
private $readWatcher;
/** @var string onWritable loop watcher. */
private $writeWatcher;
/** @var \SplQueue Queue of pending reads. */
private $reads;
/** @var \SplQueue Queue of pending writes. */
private $writes;
/** @var bool */
private $open = true;
/** @var bool */
private $autoClose = true;
/**
* @param resource $read Readable stream resource.
* @param resource $write Writable stream resource.
@ -42,28 +46,28 @@ class ChannelledSocket implements Channel {
if (!\is_resource($read) || \get_resource_type($read) !== 'stream') {
throw new \Error('Invalid resource given to constructor!');
}
if (!\is_resource($write) || \get_resource_type($write) !== 'stream') {
throw new \Error('Invalid resource given to constructor!');
}
$this->readResource = $read;
$this->writeResource = $write;
$this->autoClose = $autoClose;
\stream_set_blocking($this->readResource, false);
\stream_set_read_buffer($this->readResource, 0);
\stream_set_write_buffer($this->readResource, 0);
if ($this->readResource !== $this->writeResource) {
\stream_set_blocking($this->writeResource, false);
\stream_set_read_buffer($this->writeResource, 0);
\stream_set_write_buffer($this->writeResource, 0);
}
$this->reads = $reads = new \SplQueue;
$this->writes = $writes = new \SplQueue;
$errorHandler = static function ($errno, $errstr, $errfile, $errline) {
if ($errno & \error_reporting()) {
throw new ChannelException(\sprintf(
@ -75,56 +79,56 @@ class ChannelledSocket implements Channel {
));
}
};
$this->readWatcher = Loop::onReadable($this->readResource, static function ($watcher, $stream) use ($reads, $errorHandler) {
while (!$reads->isEmpty()) {
/** @var \Amp\Deferred $deferred */
list($buffer, $length, $deferred) = $reads->shift();
if ($length === 0) {
// Error reporting suppressed since fread() produces a warning if the stream unexpectedly closes.
$data = @\fread($stream, self::HEADER_LENGTH - \strlen($buffer));
if ($data === false || ($data === '' && (\feof($stream) || !\is_resource($stream)))) {
$deferred->fail(new ChannelException("The socket unexpectedly closed"));
break;
}
$buffer .= $data;
if (\strlen($buffer) !== self::HEADER_LENGTH) {
// Not enough data available.
$reads->unshift([$buffer, 0, $deferred]);
return;
}
$data = \unpack("Cprefix/Llength", $data);
if ($data["prefix"] !== 0) {
$deferred->fail(new ChannelException("Invalid header received"));
break;
}
$length = $data["length"];
$buffer = '';
}
// Error reporting suppressed since fread() produces a warning if the stream unexpectedly closes.
$data = @\fread($stream, $length - \strlen($buffer));
if ($data === false || ($data === '' && (\feof($stream) || !\is_resource($stream)))) {
$deferred->fail(new ChannelException("The socket unexpectedly closed"));
break;
}
$buffer .= $data;
if (\strlen($buffer) < $length) {
// Not enough data available.
$reads->unshift([$buffer, $length, $deferred]);
return;
}
\set_error_handler($errorHandler);
try {
@ -140,10 +144,10 @@ class ChannelledSocket implements Channel {
$deferred->fail(new SerializationException("Exception thrown when unserializing data", $exception));
}
}
Loop::disable($watcher);
});
$this->writeWatcher = Loop::onWritable($this->writeResource, static function ($watcher, $stream) use ($writes) {
try {
while (!$writes->isEmpty()) {
@ -167,7 +171,7 @@ class ChannelledSocket implements Channel {
$exception = new ChannelException($message);
$deferred->fail($exception);
while (!$writes->isEmpty()) {
list( , , $deferred) = $writes->shift();
list(, , $deferred) = $writes->shift();
$deferred->fail($exception);
}
return;
@ -188,17 +192,17 @@ class ChannelledSocket implements Channel {
}
}
});
Loop::disable($this->readWatcher);
Loop::disable($this->writeWatcher);
}
public function __destruct() {
if ($this->readResource !== null) {
$this->close();
}
}
/**
* {@inheritdoc}
*/
@ -206,7 +210,7 @@ class ChannelledSocket implements Channel {
if (\is_resource($this->readResource)) {
if ($this->autoClose) {
@\fclose($this->readResource);
if ($this->readResource !== $this->writeResource) {
@\fclose($this->writeResource);
}
@ -214,23 +218,23 @@ class ChannelledSocket implements Channel {
$this->readResource = null;
$this->writeResource = null;
}
$this->open = false;
if (!$this->reads->isEmpty()) {
$exception = new ChannelException("The connection was unexpectedly closed before reading completed");
do {
/** @var \Amp\Deferred $deferred */
list( , , $deferred) = $this->reads->shift();
list(, , $deferred) = $this->reads->shift();
$deferred->fail($exception);
} while (!$this->reads->isEmpty());
}
if (!$this->writes->isEmpty()) {
$exception = new ChannelException("The connection was unexpectedly writing completed");
do {
/** @var \Amp\Deferred $deferred */
list( , , $deferred) = $this->writes->shift();
list(, , $deferred) = $this->writes->shift();
$deferred->fail($exception);
} while (!$this->writes->isEmpty());
}
@ -238,7 +242,7 @@ class ChannelledSocket implements Channel {
Loop::cancel($this->readWatcher);
Loop::cancel($this->writeWatcher);
}
/**
* {@inheritdoc}
*/
@ -246,13 +250,13 @@ class ChannelledSocket implements Channel {
if (!$this->open) {
return new Failure(new ChannelException("The channel is has been closed"));
}
$deferred = new Deferred;
$this->reads->push(["", 0, $deferred]);
Loop::enable($this->readWatcher);
return $deferred->promise();
}
/**
* @param string $data
* @param bool $end
@ -272,7 +276,7 @@ class ChannelledSocket implements Channel {
"The given data cannot be sent because it is not serializable.", $exception
);
}
$data = \pack("CL", 0, \strlen($data)) . $data;
$length = \strlen($data);
$written = 0;
@ -280,7 +284,7 @@ class ChannelledSocket implements Channel {
if ($this->writes->isEmpty()) {
// Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full.
$written = @\fwrite($this->writeResource, $data);
if ($written === false) {
$message = "Failed to write to stream";
if ($error = \error_get_last()) {
@ -288,11 +292,11 @@ class ChannelledSocket implements Channel {
}
return new Failure(new ChannelException($message));
}
if ($length <= $written) {
return new Success($written);
}
$data = \substr($data, $written);
}
@ -301,4 +305,4 @@ class ChannelledSocket implements Channel {
Loop::enable($this->writeWatcher);
return $deferred->promise();
}
}
}

View File

@ -2,8 +2,12 @@
namespace Amp\Parallel\Sync;
use Amp\{ Coroutine, Promise };
use Amp\ByteStream\{ InputStream, OutputStream, Parser, StreamException };
use Amp\ByteStream\InputStream;
use Amp\ByteStream\OutputStream;
use Amp\ByteStream\Parser;
use Amp\ByteStream\StreamException;
use Amp\Coroutine;
use Amp\Promise;
/**
* An asynchronous channel for sending data between threads and processes.

View File

@ -4,7 +4,6 @@ namespace Amp\Parallel\Sync;
use Amp\Coroutine;
use Amp\Delayed;
use Amp\Pause;
use Amp\Parallel\MutexException;
use Amp\Promise;

View File

@ -39,4 +39,4 @@ class ExitFailure implements ExitResult {
$this->trace
);
}
}
}

View File

@ -16,4 +16,4 @@ class ExitSuccess implements ExitResult {
public function getResult() {
return $this->result;
}
}
}

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel\Sync;
class LockAlreadyReleasedError extends \Error {}
class LockAlreadyReleasedError extends \Error {
}

View File

@ -11,8 +11,7 @@ use Amp\Promise;
* are atomic. Implementations do not have to guarantee that acquiring a lock
* is first-come, first serve.
*/
interface Mutex
{
interface Mutex {
/**
* @coroutine
*

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel\Sync;
class MutexException extends \Exception {}
class MutexException extends \Exception {
}

View File

@ -123,7 +123,7 @@ class PosixSemaphore implements Semaphore, \Serializable {
public function acquire(): Promise {
return new Coroutine($this->doAcquire());
}
/**
* {@inheritdoc}
*/

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel\Sync;
class SemaphoreException extends \Exception {}
class SemaphoreException extends \Exception {
}

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel\Sync;
class SerializationException extends ChannelException {}
class SerializationException extends ChannelException {
}

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel\Sync;
class SharedMemoryException extends \Exception {}
class SharedMemoryException extends \Exception {
}

View File

@ -2,7 +2,8 @@
namespace Amp\Parallel\Sync;
use Amp\{ Coroutine, Promise };
use Amp\Coroutine;
use Amp\Promise;
/**
* A container object for sharing a value across contexts.
@ -164,7 +165,7 @@ class SharedMemoryParcel implements Parcel, \Serializable {
public function synchronized(callable $callback): Promise {
return new Coroutine($this->doSynchronized($callback));
}
/**
* @coroutine
*
@ -175,28 +176,28 @@ class SharedMemoryParcel implements Parcel, \Serializable {
private function doSynchronized(callable $callback): \Generator {
/** @var \Amp\Parallel\Sync\Lock $lock */
$lock = yield $this->semaphore->acquire();
try {
$value = $this->unwrap();
$result = $callback($value);
if ($result instanceof \Generator) {
$result = new Coroutine($result);
}
if ($result instanceof Promise) {
$result = yield $result;
}
$this->wrap(null === $result ? $value : $result);
} finally {
$lock->release();
}
return $result;
}
/**
* Frees the shared object from memory.
*

View File

@ -2,4 +2,5 @@
namespace Amp\Parallel;
class SynchronizationError extends \Error {}
class SynchronizationError extends \Error {
}

View File

@ -15,14 +15,14 @@ class Mutex extends \Threaded {
/** @var bool */
private $lock = true;
/**
* @return \Amp\Promise
*/
public function acquire(): Promise {
return new Coroutine($this->doAcquire());
}
/**
* Attempts to acquire the lock and sleeps for a time if the lock could not be acquired.
*

View File

@ -42,7 +42,7 @@ class Semaphore extends \Threaded {
public function acquire(): Promise {
return new Coroutine($this->doAcquire());
}
/**
* Uses a double locking mechanism to acquire a lock without blocking. A
* synchronous mutex is used to make sure that the semaphore is queried one

View File

@ -2,15 +2,15 @@
namespace Amp\Parallel\Threading\Internal;
use Amp\{ Coroutine, Loop, Promise };
use Amp\Parallel\Sync\{
Channel,
ChannelException,
ChannelledSocket,
Internal\ExitFailure,
Internal\ExitSuccess,
SerializationException
};
use Amp\Coroutine;
use Amp\Loop;
use Amp\Parallel\Sync\Channel;
use Amp\Parallel\Sync\ChannelException;
use Amp\Parallel\Sync\ChannelledSocket;
use Amp\Parallel\Sync\Internal\ExitFailure;
use Amp\Parallel\Sync\Internal\ExitSuccess;
use Amp\Parallel\Sync\SerializationException;
use Amp\Promise;
/**
* An internal thread that executes a given function concurrently.

View File

@ -2,8 +2,8 @@
namespace Amp\Parallel\Threading;
use Amp\Promise;
use Amp\Parallel\Sync\Mutex as SyncMutex;
use Amp\Promise;
/**
* A thread-safe, asynchronous mutex using the pthreads locking mechanism.

View File

@ -2,8 +2,9 @@
namespace Amp\Parallel\Threading;
use Amp\{ Coroutine, Promise };
use Amp\Coroutine;
use Amp\Parallel\Sync\Parcel as SyncParcel;
use Amp\Promise;
/**
* A thread-safe container that shares a value between multiple threads.
@ -52,7 +53,7 @@ class Parcel implements SyncParcel {
public function synchronized(callable $callback): Promise {
return new Coroutine($this->doSynchronized($callback));
}
/**
* @coroutine
*
@ -70,15 +71,15 @@ class Parcel implements SyncParcel {
try {
$value = $this->unwrap();
$result = $callback($value);
if ($result instanceof \Generator) {
$result = new Coroutine($result);
}
if ($result instanceof Promise) {
$result = yield $result;
}
$this->wrap(null === $result ? $value : $result);
} finally {
$lock->release();

View File

@ -2,8 +2,8 @@
namespace Amp\Parallel\Threading;
use Amp\Promise;
use Amp\Parallel\Sync\Semaphore as SyncSemaphore;
use Amp\Promise;
/**
* An asynchronous semaphore based on pthreads' synchronization methods.

View File

@ -2,10 +2,17 @@
namespace Amp\Parallel\Threading;
use Amp\Coroutine;
use Amp\Loop;
use Amp\Parallel\ContextException;
use Amp\Parallel\StatusError;
use Amp\Parallel\Strand;
use Amp\Parallel\Sync\ChannelException;
use Amp\Parallel\Sync\ChannelledSocket;
use Amp\Parallel\Sync\Internal\ExitResult;
use Amp\Parallel\SynchronizationError;
use Amp\Promise;
use function Amp\call;
use Amp\{ Coroutine, Loop, Promise };
use Amp\Parallel\{ ContextException, StatusError, SynchronizationError, Strand };
use Amp\Parallel\Sync\{ ChannelException, ChannelledSocket, Internal\ExitResult };
/**
* Implements an execution context using native multi-threading.

View File

@ -2,9 +2,14 @@
namespace Amp\Parallel\Worker;
use Amp\{ Coroutine, Deferred, Promise };
use Amp\Parallel\{ StatusError, Strand } ;
use Amp\Parallel\Worker\Internal\{ Job, TaskResult };
use Amp\Coroutine;
use Amp\Deferred;
use Amp\Parallel\StatusError;
use Amp\Parallel\Strand;
use Amp\Parallel\Worker\Internal\Job;
use Amp\Parallel\Worker\Internal\TaskResult;
use Amp\Promise;
/**
* Base class for most common types of task workers.
@ -15,10 +20,10 @@ abstract class AbstractWorker implements Worker {
/** @var bool */
private $shutdown = false;
/** @var \Amp\Deferred[] */
private $jobQueue = [];
/** @var callable */
private $when;
@ -27,32 +32,32 @@ abstract class AbstractWorker implements Worker {
*/
public function __construct(Strand $strand) {
$this->context = $strand;
$this->when = function ($exception, $data) {
if ($exception) {
$this->kill();
return;
}
if (!$data instanceof TaskResult) {
$this->kill();
return;
}
$id = $data->getId();
if (!isset($this->jobQueue[$id])) {
$this->kill();
return;
}
$deferred = $this->jobQueue[$id];
unset($this->jobQueue[$id]);
if (!empty($this->jobQueue)) {
$this->context->receive()->onResolve($this->when);
}
$deferred->resolve($data->promise());
};
}
@ -85,11 +90,11 @@ abstract class AbstractWorker implements Worker {
if (!$this->context->isRunning()) {
throw new StatusError('The worker has not been started.');
}
if ($this->shutdown) {
throw new StatusError('The worker has been shut down.');
}
return new Coroutine($this->doEnqueue($task));
}
@ -108,7 +113,7 @@ abstract class AbstractWorker implements Worker {
if (empty($this->jobQueue)) {
$this->context->receive()->onResolve($this->when);
}
try {
$job = new Job($task);
$this->jobQueue[$job->getId()] = $deferred = new Deferred;
@ -117,7 +122,7 @@ abstract class AbstractWorker implements Worker {
$this->kill();
throw new WorkerException('Sending the task to the worker failed.', $exception);
}
return yield $deferred->promise();
}
@ -128,7 +133,7 @@ abstract class AbstractWorker implements Worker {
if (!$this->context->isRunning() || $this->shutdown) {
throw new StatusError('The worker is not running.');
}
return new Coroutine($this->doShutdown());
}
@ -161,11 +166,11 @@ abstract class AbstractWorker implements Worker {
private function cancelPending() {
if (!empty($this->jobQueue)) {
$exception = new WorkerException('Worker was shut down.');
foreach ($this->jobQueue as $job) {
$job->fail($exception);
}
$this->jobQueue = [];
}
}

View File

@ -43,7 +43,7 @@ class BasicEnvironment implements Environment {
Loop::disable($this->timer);
}
});
Loop::disable($this->timer);
Loop::unreference($this->timer);
}
@ -70,7 +70,7 @@ class BasicEnvironment implements Environment {
return isset($this->data[$key]) ? $this->data[$key] : null;
}
/**
* @param string $key
* @param mixed $value Using null for the value deletes the key.

View File

@ -2,8 +2,10 @@
namespace Amp\Parallel\Worker;
use Amp\{ CallableMaker, Coroutine, Promise };
use Amp\CallableMaker;
use Amp\Coroutine;
use Amp\Parallel\StatusError;
use Amp\Promise;
/**
* Provides a pool of workers that can be used to execute multiple tasks asynchronously.
@ -14,7 +16,7 @@ use Amp\Parallel\StatusError;
*/
class DefaultPool implements Pool {
use CallableMaker;
/** @var bool Indicates if the pool is currently running. */
private $running = false;
@ -156,7 +158,7 @@ class DefaultPool implements Pool {
public function enqueue(Task $task): Promise {
return new Coroutine($this->doEnqueue($this->pull(), $task));
}
/**
* @coroutine
*
@ -173,7 +175,7 @@ class DefaultPool implements Pool {
} finally {
$this->push($worker);
}
return $result;
}
@ -190,7 +192,7 @@ class DefaultPool implements Pool {
if (!$this->isRunning()) {
throw new StatusError('The pool is not running.');
}
return new Coroutine($this->doShutdown());
}
@ -247,7 +249,7 @@ class DefaultPool implements Pool {
public function get(): Worker {
return new Internal\PooledWorker($this->pull(), $this->push);
}
/**
* Pulls a worker from the pool. The worker should be put back into the pool with push() to be marked as idle.
*
@ -282,7 +284,7 @@ class DefaultPool implements Pool {
$this->busyQueue->push($worker);
$this->workers[$worker] += 1;
return $worker;
}

View File

@ -7,19 +7,19 @@ use Amp\Parallel\Worker\Task;
class Job {
/** @var string */
private $id;
/** @var \Amp\Parallel\Worker\Task */
private $task;
public function __construct(Task $task) {
$this->task = $task;
$this->id = \spl_object_hash($this->task);
}
public function getId(): string {
return $this->id;
}
public function getTask(): Task {
return $this->task;
}

View File

@ -2,7 +2,8 @@
namespace Amp\Parallel\Worker\Internal;
use Amp\Parallel\Worker\{ Task, Worker };
use Amp\Parallel\Worker\Task;
use Amp\Parallel\Worker\Worker;
use Amp\Promise;
class PooledWorker implements Worker {
@ -69,4 +70,4 @@ class PooledWorker implements Worker {
public function kill() {
$this->worker->kill();
}
}
}

View File

@ -34,7 +34,7 @@ class TaskFailure extends TaskResult {
$this->code = $exception->getCode();
$this->trace = $exception->getTraceAsString();
}
public function promise(): Promise {
switch ($this->parent) {
case self::PARENT_ERROR:
@ -57,4 +57,4 @@ class TaskFailure extends TaskResult {
return new Failure($exception);
}
}
}

View File

@ -7,23 +7,23 @@ use Amp\Promise;
abstract class TaskResult {
/** @var string Task identifier. */
private $id;
/**
* @param string $id Task identifier.
*/
public function __construct(string $id) {
$this->id = $id;
}
/**
* @return string Task identifier.
*/
public function getId(): string {
return $this->id;
}
/**
* @return \Amp\Promise<mixed> Resolved with the task result or failure reason.
*/
abstract public function promise(): Promise;
}
}

View File

@ -2,9 +2,12 @@
namespace Amp\Parallel\Worker\Internal;
use Amp\{ Coroutine, Failure, Success };
use Amp\Parallel\{ Sync\Channel, Worker\Environment };
use Amp\Coroutine;
use Amp\Failure;
use Amp\Parallel\Sync\Channel;
use Amp\Parallel\Worker\Environment;
use Amp\Promise;
use Amp\Success;
class TaskRunner {
/** @var \Amp\Parallel\Sync\Channel */
@ -17,7 +20,7 @@ class TaskRunner {
$this->channel = $channel;
$this->environment = $environment;
}
/**
* Runs the task runner, receiving tasks from the parent and sending the result of those tasks.
*
@ -26,7 +29,7 @@ class TaskRunner {
public function run(): Promise {
return new Coroutine($this->execute());
}
/**
* @coroutine
*
@ -37,28 +40,28 @@ class TaskRunner {
while ($job instanceof Job) {
$task = $job->getTask();
try {
$result = $task->run($this->environment);
if ($result instanceof \Generator) {
$result = new Coroutine($result);
}
if (!$result instanceof Promise) {
$result = new Success($result);
}
} catch (\Throwable $exception) {
$result = new Failure($exception);
}
$result->onResolve(function ($exception, $value) use ($job) {
if ($exception) {
$result = new TaskFailure($job->getId(), $exception);
} else {
$result = new TaskSuccess($job->getId(), $value);
}
$this->channel->send($result);
});

View File

@ -2,18 +2,18 @@
namespace Amp\Parallel\Worker\Internal;
use Amp\Success;
use Amp\Promise;
use Amp\Success;
class TaskSuccess extends TaskResult {
/** @var mixed Result of task. */
private $result;
public function __construct(string $id, $result) {
parent::__construct($id);
$this->result = $result;
}
public function promise(): Promise {
return new Success($this->result);
}

View File

@ -20,7 +20,7 @@ class TaskError extends \Error {
$this->name = $name;
$this->trace = $trace;
}
/**
* Returns the class name of the error thrown from the task.
*
@ -29,7 +29,7 @@ class TaskError extends \Error {
public function getName(): string {
return $this->name;
}
/**
* Gets the stack trace at the point the error was thrown in the task.
*

View File

@ -20,7 +20,7 @@ class TaskException extends \Exception {
$this->name = $name;
$this->trace = $trace;
}
/**
* Returns the class name of the exception thrown from the task.
*
@ -29,7 +29,7 @@ class TaskException extends \Exception {
public function getName(): string {
return $this->name;
}
/**
* Gets the stack trace at the point the exception was thrown in the task.
*

View File

@ -2,9 +2,9 @@
namespace Amp\Parallel\Worker;
use Amp\Promise;
use Amp\Parallel\Threading\Thread;
use Amp\Parallel\Worker\Internal\TaskRunner;
use Amp\Promise;
/**
* A worker thread that executes task objects.

View File

@ -2,7 +2,8 @@
namespace Amp\Parallel\Worker;
use Amp\{ Loop, Promise };
use Amp\Loop;
use Amp\Promise;
const LOOP_POOL_IDENTIFIER = Pool::class;
const LOOP_FACTORY_IDENTIFIER = WorkerFactory::class;

View File

@ -113,7 +113,6 @@ abstract class AbstractContextTest extends TestCase {
$context->start();
yield $context->join();
});
}, 1000);
}

View File

@ -2,9 +2,9 @@
namespace Amp\Parallel\Test\Forking;
use Amp\Loop;
use Amp\Parallel\Forking\Fork;
use Amp\Parallel\Test\AbstractContextTest;
use Amp\Loop;
/**
* @group forking

View File

@ -96,13 +96,13 @@ abstract class AbstractSemaphoreTest extends TestCase {
$callback = function () {
$awaitable1 = $this->semaphore->acquire();
$awaitable2 = $this->semaphore->acquire();
yield new Delayed(500);
(yield $awaitable1)->release();
yield new Delayed(500);
(yield $awaitable2)->release();
};

View File

@ -20,7 +20,7 @@ class ChannelledSocketTest extends TestCase {
}
return $sockets;
}
public function testSendReceive() {
Loop::run(function () {
list($left, $right) = $this->createSockets();
@ -54,7 +54,6 @@ class ChannelledSocketTest extends TestCase {
$data = yield $b->receive();
$this->assertSame($message, $data);
});
}
/**
@ -70,7 +69,6 @@ class ChannelledSocketTest extends TestCase {
fwrite($left, pack('L', 10) . '1234567890');
$data = yield $b->receive();
});
}
/**
@ -87,7 +85,6 @@ class ChannelledSocketTest extends TestCase {
yield $a->send(function () {});
$data = yield $b->receive();
});
}
/**
@ -102,7 +99,6 @@ class ChannelledSocketTest extends TestCase {
yield $a->send('hello');
});
}
/**
@ -117,6 +113,5 @@ class ChannelledSocketTest extends TestCase {
$data = yield $a->receive();
});
}
}

View File

@ -3,8 +3,8 @@
namespace Amp\Parallel\Test\Sync;
use Amp\ByteStream\InputStream;
use Amp\ByteStream\StreamException;
use Amp\ByteStream\OutputStream;
use Amp\ByteStream\StreamException;
use Amp\Loop;
use Amp\Parallel\Sync\ChannelledStream;
use Amp\PHPUnit\TestCase;
@ -73,7 +73,6 @@ class ChannelledStreamTest extends TestCase {
$data = yield $b->receive();
$this->assertSame($message, $data);
});
}
/**
@ -90,7 +89,6 @@ class ChannelledStreamTest extends TestCase {
yield $mock->write(pack('L', 10) . '1234567890');
$data = yield $b->receive();
});
}
/**
@ -107,7 +105,6 @@ class ChannelledStreamTest extends TestCase {
yield $a->send(function () {});
$data = yield $b->receive();
});
}
/**
@ -129,7 +126,6 @@ class ChannelledStreamTest extends TestCase {
yield $a->send('hello');
});
}
/**
@ -147,6 +143,5 @@ class ChannelledStreamTest extends TestCase {
$data = yield $a->receive();
});
}
}

View File

@ -14,7 +14,6 @@ class FileMutexTest extends TestCase {
$lock->release();
$this->assertTrue($lock->isReleased());
});
}
public function testAcquireMultiple() {

View File

@ -2,9 +2,10 @@
namespace Amp\Parallel\Test\Sync;
use Amp\Parallel\Forking\Fork;
use Amp\Parallel\Sync\{ PosixSemaphore, Semaphore };
use Amp\Loop;
use Amp\Parallel\Forking\Fork;
use Amp\Parallel\Sync\PosixSemaphore;
use Amp\Parallel\Sync\Semaphore;
/**
* @group posix
@ -40,7 +41,6 @@ class PosixSemaphoreTest extends AbstractSemaphoreTest {
$clone->free();
});
}
public function testFree() {

View File

@ -18,7 +18,6 @@ class MutexTest extends TestCase {
$lock->release();
$this->assertTrue($lock->isReleased());
});
}
public function testAcquireMultiple() {

View File

@ -2,8 +2,8 @@
namespace Amp\Parallel\Test\Threading;
use Amp\Parallel\Threading\Parcel;
use Amp\Parallel\Test\Sync\AbstractParcelTest;
use Amp\Parallel\Threading\Parcel;
/**
* @requires extension pthreads

View File

@ -4,8 +4,9 @@ namespace Amp\Parallel\Test\Threading;
use Amp\Loop;
use Amp\Parallel\Sync\Semaphore as SyncSemaphore;
use Amp\Parallel\Threading\{Semaphore, Thread};
use Amp\Parallel\Test\Sync\AbstractSemaphoreTest;
use Amp\Parallel\Threading\Semaphore;
use Amp\Parallel\Threading\Thread;
/**
* @group threading

View File

@ -3,8 +3,8 @@
namespace Amp\Parallel\Test\Threading;
use Amp\Loop;
use Amp\Parallel\Threading\Thread;
use Amp\Parallel\Test\AbstractContextTest;
use Amp\Parallel\Threading\Thread;
/**
* @group threading
@ -25,6 +25,5 @@ class ThreadTest extends AbstractContextTest {
return yield $thread->join();
});
}
}

View File

@ -51,7 +51,7 @@ abstract class AbstractWorkerTest extends TestCase {
Loop::run(function () {
$worker = $this->createWorker();
$worker->start();
$values = yield \Amp\Promise\all([
$worker->enqueue(new TestTask(42)),
$worker->enqueue(new TestTask(56)),

View File

@ -3,10 +3,13 @@
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker;
use Amp\Parallel\Worker\{ Environment, Pool, Task, WorkerFactory };
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Pool;
use Amp\Parallel\Worker\Task;
use Amp\Parallel\Worker\WorkerFactory;
use Amp\PHPUnit\TestCase;
use Amp\Success;
use Amp\Promise;
use Amp\Success;
class FunctionsTest extends TestCase {
public function testPool() {

View File

@ -2,7 +2,9 @@
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker\{ DefaultPool, WorkerFactory, WorkerProcess };
use Amp\Parallel\Worker\DefaultPool;
use Amp\Parallel\Worker\WorkerFactory;
use Amp\Parallel\Worker\WorkerProcess;
/**
* @group process

View File

@ -2,7 +2,8 @@
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker\{ Environment, Task };
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
class TestTask implements Task {
private $returnValue;

View File

@ -2,7 +2,9 @@
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker\{ DefaultPool, WorkerFactory, WorkerThread };
use Amp\Parallel\Worker\DefaultPool;
use Amp\Parallel\Worker\WorkerFactory;
use Amp\Parallel\Worker\WorkerThread;
/**
* @group threading