-
Notifications
You must be signed in to change notification settings - Fork 0
ManagedTask Documentation (Russian)
ManagedTask - это класс, который предоставляет возможность выполнять и управлять асинхронными задачами в PHP. Он поддерживает продолжение задач, паузу, возобновление и отмену. Эта документация объясняет, как использовать ManagedTask в ваших PHP приложениях, с подробными объяснениями и примерами.
-
Id
: int - Получает уникальный идентификатор задачи. -
Status
: TaskStatus - Получает текущий статус задачи. -
IsCompleted
: bool - Указывает, завершена ли задача. -
IsCanceled
: bool - Указывает, была ли задача отменена. -
IsCompletedSuccessfully
: bool - Указывает, завершена ли задача успешно. -
IsFaulted
: bool - Указывает, произошла ли ошибка в задаче. -
IsPaused
: bool - Указывает, приостановлена ли задача. -
IsStarted
: bool - Указывает, запущена ли задача.
-
Completed
: event(EventHandler) - Возникает, когда задача завершена.
//Инициализирует новый экземпляр класса ManagedTask.
public function __construct(callable $callable, ManagedTaskCreationOptions $options = ManagedTaskCreationOptions::None)
- $callable: callable - PHP callable для выполнения в качестве задачи.
- $options: ManagedTaskCreationOptions - Опции для создания задачи.
//Запускает задачу.
public function Start();
// Создает и запускает новую задачу.
public static function Run(callable $callable, ManagedTaskCreationOptions $options = ManagedTaskCreationOptions::None): ManagedTask
- $callable: callable - PHP callable для выполнения в качестве задачи.
- $options: ManagedTaskCreationOptions - Опции для создания задачи.
//Приостанавливает задачу.
public function Pause();
//Возобновляет задачу, если она была приостановлена.
public function Resume();
//Останавливает задачу.
public function Stop();
Ожидает завершения задачи.
public function Wait();
// Ожидает завершения всех переданных задач.
public static function WaitAll(array $managedTasks): void
- $managedTasks: array - PHP массив объектов ManagedTask.\
// Ожидает завершения любой из переданных задач.
public static function WaitAny(array $managedTasks): int
- $managedTasks: array - PHP массив объектов ManagedTask.
- Возвращает индекс первой завершившейся задачи.
//Синхронно получает результат задачи.
public function GetResultSync();
//Создает задачу-продолжение, которая выполняется при завершении текущей задачи.
public function ContinueWith(callable $continuationAction, ManagedTaskCreationOptions $options = ManagedTaskCreationOptions::None): ManagedTask
- $continuationAction: callable - Действие, которое нужно выполнить при завершении задачи.
- $options: ManagedTaskCreationOptions - Опции для создания задачи-продолжения.
//Освобождает задачу и её ресурсы.
public function Dispose();
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Output\Logger;
function simpleTask() {
// Симуляция работы
sleep(2);
return "Задача выполнена";
}
$managedTask = new ManagedTask('simpleTask');
$managedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
Logger::Info("Задача {$e->TaskId} завершена с результатом: {$e->Result}");
});
$managedTask->Start();
$managedTask->Wait();
В этом примере мы демонстрируем, как можно использовать метод Run для создания и запуска задач последовательно:
- Первая задача fetchData симулирует получение данных и запускается с помощью ManagedTask::Run.
- После завершения первой задачи запускается вторая задача processData, которая обрабатывает полученные данные и имеет опцию ManagedTaskCreationOptions::AttachedToParent, указывающую, что задача является дочерней по отношению к родительской.
- После завершения второй задачи запускается третья задача saveData, которая сохраняет обработанные данные и также имеет опцию ManagedTaskCreationOptions::AttachedToParent.
- Все задачи связаны между собой с использованием событий Completed, чтобы каждая последующая задача запускалась при завершении предыдущей.
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskCreationOptions;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Output\Logger;
function fetchData(): string {
sleep(2); // Симуляция задержки запроса
return "Данные получены";
}
function processData(string $data): string {
sleep(1); // Симуляция обработки данных
return "Обработанные данные: $data";
}
function saveData(string $data): string {
sleep(1); // Симуляция сохранения данных
return "Данные сохранены: $data";
}
// Создаем и запускаем задачу получения данных
$fetchTask = ManagedTask::Run('fetchData');
$fetchTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
$data = $e->Result;
Logger::Info("Получены данные: $data");
// Создаем и запускаем задачу обработки данных при завершении первой задачи
$processTask = ManagedTask::Run(function() use ($data) {
return processData($data);
} , ManagedTaskCreationOptions::AttachedToParent);
$processTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
$processedData = $e->Result;
Logger::Info("Обработаны данные: $processedData");
// Создаем и запускаем задачу сохранения данных при завершении второй задачи
$saveTask = ManagedTask::Run(function() use ($processedData) {
return saveData($processedData);
} , ManagedTaskCreationOptions::AttachedToParent);
$saveTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
Logger::Info($e->Result);
});
});
});
$fetchTask->Wait();
В этом примере мы демонстрируем, как можно использовать метод WaitAll для ожидания завершения всех задач в массиве:
- Создаем три задачи: task1, task2 и task3, каждая из которых выполняет свою работу с разной задержкой.
- Помещаем созданные задачи в массив $tasks.
- Используем метод ManagedTask::WaitAll для ожидания завершения всех задач в массиве.
- После завершения всех задач выводится сообщение "Все задачи завершены".
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Output\Logger;
function task1(): string {
sleep(2);
return "Задача 1 выполнена";
}
function task2(): string {
sleep(3);
return "Задача 2 выполнена";
}
function task3(): string {
sleep(1);
return "Задача 3 выполнена";
}
$task1 = ManagedTask::Run('task1');
$task2 = ManagedTask::Run('task2');
$task3 = ManagedTask::Run('task3');
$tasks = [$task1, $task2, $task3];
// Ожидаем завершения всех задач
ManagedTask::WaitAll($tasks);
Logger::Info("Все задачи завершены");
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskCreationOptions;
use Php\Output\Logger;
function task1(): string {
sleep(2);
return "Задача 1 выполнена";
}
function task2(): string {
sleep(3);
return "Задача 2 выполнена";
}
function task3(): string {
sleep(1);
return "Задача 3 выполнена";
}
$task1 = ManagedTask::Run('task1');
$task2 = ManagedTask::Run('task2');
$task3 = ManagedTask::Run('task3');
$tasks = [$task1, $task2, $task3];
// Ожидаем завершения любой задачи
$completedTaskIndex = ManagedTask::WaitAny($tasks);
Logger::Info("Задача с индексом {$completedTaskIndex} завершена первой");
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Threading\Tasks\ManagedTaskException;
use Php\Output\Logger;
/**
* @throws Exception
*/
function taskWithError() {
throw new Exception("Что-то пошло не так!");
}
$managedTask = new ManagedTask('taskWithError');
$managedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
if ($e->Result instanceof ManagedTaskException) {
Logger::Error("Ошибка задачи: {$e->Result->getMessage()}");
} else {
Logger::Info("Задача {$e->TaskId} завершена с результатом: {$e->Result}");
}
});
try {
$managedTask->Start();
$managedTask->Wait();
} catch (ManagedTaskException $ex) {
Logger::Error("Пойманная ошибка задачи: {$ex->getMessage()}");
}
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Output\Logger;
use System\Threading\AutoResetEvent;
use System\Threading\CancellationToken;
function longRunningTask(CancellationToken $cancellationToken, AutoResetEvent $autoResetEvent): string
{
for ($i = 0; $i < 10; $i++) {
if ($cancellationToken->IsCancellationRequested) {
return "Задача отменена";
}
$autoResetEvent->WaitOne(); // Механизм паузы
Logger::Info("Этап задачи: $i");
$autoResetEvent->Set();
sleep(1); // Симуляция работы
}
return "Задача выполнена";
}
$managedTask = new ManagedTask('longRunningTask');
$managedTask->Start();
sleep(3); // Дать задаче немного поработать
$managedTask->Pause();
Logger::Info("Задача приостановлена");
sleep(3); // Пауза
$managedTask->Resume();
Logger::Info("Задача возобновлена");
$managedTask->Wait();
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Output\Logger;
use System\Threading\AutoResetEvent;
use System\Threading\CancellationToken;
function initialTask(): string
{
return "Результат начальной задачи";
}
function continuationTask(CancellationToken $cancellationToken, AutoResetEvent $autoResetEvent, mixed $previousResult): string
{
return "Задача-продолжение с предыдущим результатом: $previousResult";
}
$managedTask = new ManagedTask('initialTask');
$continuedTask = $managedTask->ContinueWith('continuationTask');
$managedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
Logger::Info("Начальная задача завершена с результатом: {$e->Result}");
});
$continuedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
Logger::Info("Задача-продолжение завершена с результатом: {$e->Result}");
});
$managedTask->Start();
$managedTask->Wait();
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Threading\Tasks\ManagedTaskException;
use Php\Output\Logger;
use System\Threading\AutoResetEvent;
use System\Threading\CancellationToken;
function taskWithCatch(CancellationToken $cancellationToken, AutoResetEvent $autoResetEvent)
{
try {
// Симуляция работы
$autoResetEvent->WaitOne();
// Здесь можно вызвать ошибку
throw new Exception("Ошибка внутри задачи");
$autoResetEvent->Set();
return "Задача выполнена";
} catch (Exception $ex) {
$autoResetEvent->Set();
return new ManagedTaskException($ex->getMessage());
}
}
$managedTask = new ManagedTask('taskWithCatch');
$managedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
if ($e->Result instanceof ManagedTaskException) {
Logger::Error("Ошибка задачи: {$e->Result->getMessage()}");
} else {
Logger::Info("Задача {$e->TaskId} завершена с результатом: {$e->Result}");
}
});
$managedTask->Start();
$managedTask->Wait();
В этом примере мы используем Mutex для синхронизации доступа к критической секции кода. WaitOne на mutex блокирует текущий поток до тех пор, пока не будет получен доступ к критической секции, а ReleaseMutex освобождает этот доступ.
<?php
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Output\Logger;
use System\Threading\Mutex;
use System\Threading\AutoResetEvent;
use System\Threading\CancellationToken;
class SyncTaskExample {
private Mutex $mutex;
public function __construct() {
$this->mutex = new Mutex();
}
public function taskWithSync(CancellationToken $cancellationToken, AutoResetEvent $autoResetEvent): string
{
for ($i = 0; $i <= 10; $i++) {
if ($cancellationToken->IsCancellationRequested) {
return "Задача отменена";
}
$autoResetEvent->WaitOne();
$this->mutex->WaitOne(); // Синхронизация задачи
try {
Logger::Info("Этап задачи: $i");
} finally {
$this->mutex->ReleaseMutex();
}
$autoResetEvent->Set();
sleep(1); // Симуляция работы
}
return "Задача выполнена";
}
}
$example = new SyncTaskExample();
$managedTask = new ManagedTask([$example, 'taskWithSync']);
$managedTask->Start();
$managedTask->Wait();
Скачивание изображения из интернета и сохранение рядом с программой с помощью HttpClient и ManagedTask
В этом примере мы используем HttpClient для скачивания изображения из интернета и сохранения его на диск. GetAsync выполняет асинхронный запрос, а ReadAsStreamAsync считывает содержимое ответа как поток. Затем мы сохраняем этот поток в файл logo.png.
<?php
use Php\Threading\Tasks\ManagedTask;
use Php\Output\Logger;
use Php\Threading\Tasks\ManagedTaskEventArgs;
use Php\Threading\Tasks\ManagedTaskException;
use System\Net\Http\HttpClient;
use System\Net\Http\HttpRequestException;
use System\IO\FileStream;
use System\IO\FileMode;
use System\IO\FileAccess;
/**
* @throws ManagedTaskException
*/
function downloadImageTask($url): string
{
$httpClient = new HttpClient();
try {
$response = $httpClient->GetAsync($url)->Result;
$response->EnsureSuccessStatusCode();
$stream = $response->Content->ReadAsStreamAsync()->Result;
$filePath = __DIR__ . '/logo.png';
$fileStream = new FileStream($filePath, FileMode::Create, FileAccess::Write);
$stream->CopyTo($fileStream);
} catch (HttpRequestException $httpRequestException) {
return "Не удалось загрузить файл: " . $httpRequestException->Message;
} catch(Exception $exception) {
return "Ошибка в методе Load: " . $exception->getMessage();
} finally {
$httpClient->Dispose();
}
return "Изображение скачано и сохранено как logo.png";
}
$managedTask = new ManagedTask(function (){
return downloadImageTask("https://github.com/FibonacciFox/Peachpie.Avalonia/blob/master/Samples/Application/Assets/Logo.png?raw=true");
});
$managedTask->Completed->add(function(ManagedTask $sender, ManagedTaskEventArgs $e) {
Logger::Info($e->Result);
});
$managedTask->Start();
$managedTask->Wait();
$managedTask->Dispose();
<?php
use Php\Threading\Tasks\ManagedTask;
use Avalonia\Threading\Dispatcher;
use System\Threading\AutoResetEvent;
use System\Threading\CancellationToken;
class AvaloniaUIExample {
private $textblock;
public function __construct($textblock) {
$this->textblock = $textblock;
}
public function updateUITask(CancellationToken $cancellationToken, AutoResetEvent $autoResetEvent): string
{
$counter = 0;
while (!$cancellationToken->IsCancellationRequested) {
$autoResetEvent->WaitOne();
Dispatcher::$UIThread->Post(function() use ($counter) {
$this->textblock->Text = "Счетчик: $counter";
});
$counter++;
$autoResetEvent->Set();
sleep(1);
}
return "Обновление UI завершено";
}
}
// Предположим, что $textblock это элемент Avalonia UI, который мы хотим обновлять
$textblock = ...;
$example = new AvaloniaUIExample($textblock);
$managedTask = new ManagedTask([$example, 'updateUITask']);
$managedTask->Start();
sleep(10); // Позволяем задаче обновлять UI в течение 10 секунд
$managedTask->Stop();
$managedTask->Wait();
В этом примере мы используем Dispatcher для обновления элемента UI из асинхронной задачи. Dispatcher::$UIThread->Post позволяет выполнить код в потоке UI, обеспечивая безопасное обновление элементов интерфейса.
- $autoResetEvent->WaitOne(): Ожидает сигнал, что позволяет приостановить выполнение задачи до тех пор, пока не будет получен сигнал для продолжения.
- $autoResetEvent->Set(): Устанавливает сигнал, разрешая продолжение выполнения задачи.
- $cancellationToken->IsCancellationRequested: Проверяет, была ли запрошена отмена задачи. Если да, выполнение задачи должно быть прервано.
- $this->mutex->WaitOne(): Блокирует текущий поток до тех пор, пока не будет получен доступ к критической секции.
- $this->mutex->ReleaseMutex(): Освобождает доступ к критической секции, позволяя другим потокам войти в неё.
Test