Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# TaskFactory в C#
TaskFactory - это класс в System.Threading.Tasks, который предоставляет методы для создания и управления Task'ами. Это фабрика для создания асинхронных операций с дополнительными опциями конфигурации.
Основная идея
Вместо того чтобы напрямую использовать Task.Run(), можно использовать TaskFactory для большей гибкости:
// Task.Run - простой способ
var task1 = Task.Run(() => DoWork());
// TaskFactory - более гибкий способ
var taskFactory = new TaskFactory();
var task2 = taskFactory.StartNew(() => DoWork());
Основные методы TaskFactory
1. StartNew - Создание и запуск Task
var factory = new TaskFactory();
// Простой запуск
var task = factory.StartNew(() =>
{
Console.WriteLine("Work started");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Work completed");
});
await task;
// С результатом
var taskWithResult = factory.StartNew(() =>
{
return CalculatePi();
});
var result = await taskWithResult; // double
Console.WriteLine($"Pi = {result}");
2. ContinueWhenAll - Выполнение после всех Task'ов
var factory = new TaskFactory();
// Создаём несколько задач
var task1 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(1000);
return "Task 1 done";
});
var task2 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(2000);
return "Task 2 done";
});
var task3 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(500);
return "Task 3 done";
});
// Продолжение после ВСЕХ задач
var continuation = factory.ContinueWhenAll(
new[] { task1, task2, task3 },
tasks =>
{
Console.WriteLine("All tasks completed!");
foreach (var t in tasks)
{
var result = ((Task<string>)t).Result;
Console.WriteLine(result);
}
}
);
await continuation;
3. ContinueWhenAny - Выполнение после любого Task'а
var factory = new TaskFactory();
var task1 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(3000);
return "First";
});
var task2 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(1000);
return "Second";
});
// Продолжение после ПЕРВОГО завершённого
var continuation = factory.ContinueWhenAny(
new Task[] { task1, task2 },
task =>
{
var result = ((Task<string>)task).Result;
Console.WriteLine($"First completed: {result}");
}
);
await continuation;
TaskFactory с опциями
// С опциями планирования
var factory = new TaskFactory(
CancellationToken.None, // Токен отмены
TaskCreationOptions.LongRunning, // Опции создания
TaskScheduler.Default // Планировщик
);
var task = factory.StartNew(() =>
{
// Длительная операция
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
Console.WriteLine($"Iteration {i}");
}
});
TaskCreationOptions
var factory = new TaskFactory();
// LongRunning - создаёт отдельный поток для долгих операций
var longTask = factory.StartNew(
() => { /* долгая операция */ },
TaskCreationOptions.LongRunning
);
// AttachedToParent - связывает с родительским Task'ом
var parentTask = Task.Run(() =>
{
var childTask = factory.StartNew(
() => Console.WriteLine("Child"),
TaskCreationOptions.AttachedToParent
);
});
await parentTask; // Ждёт и детей
// DenyChildAttach - запрещает детским Task'ам привязываться
var restrictedFactory = new TaskFactory(
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default
);
TaskFactory vs Task.Run
// Task.Run - более простой и современный способ
var task1 = Task.Run(() => DoWork());
var task2 = Task.Run(async () => await DoWorkAsync());
// TaskFactory - более гибкий контроль
var factory = new TaskFactory(
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Current
);
var task3 = factory.StartNew(() => DoWork());
// Практически эквивалентно
var task4 = Task.Factory.StartNew(() => DoWork());
Практические примеры
Пример 1: Параллельная обработка данных
public async Task ProcessDataInParallel()
{
var factory = new TaskFactory();
var data = Enumerable.Range(1, 100).ToList();
var tasks = data
.Select(item => factory.StartNew(() =>
{
Console.WriteLine($"Processing {item} on thread {Thread.CurrentThread.ManagedThreadId}");
return item * 2;
}))
.ToList();
var results = await Task.WhenAll(tasks);
Console.WriteLine($"Processed {results.Length} items");
}
Пример 2: Цепочка операций
public async Task ChainedOperations()
{
var factory = new TaskFactory();
// Первая операция
var task1 = factory.StartNew(() =>
{
System.Threading.Thread.Sleep(1000);
return "Step 1 complete";
});
// Вторая операция после первой
var task2 = factory.ContinueWith(task1, t =>
{
var previous = t.Result;
System.Threading.Thread.Sleep(500);
return $"{previous}, Step 2 complete";
});
// Третья операция после второй
var task3 = factory.ContinueWith(task2, t =>
{
var previous = t.Result;
System.Threading.Thread.Sleep(500);
return $"{previous}, Step 3 complete";
});
var result = await task3;
Console.WriteLine(result);
}
Пример 3: Отмена операций
public async Task CancellableOperation()
{
var cts = new CancellationTokenSource();
var factory = new TaskFactory(cts.Token);
var task = factory.StartNew(() =>
{
for (int i = 0; i < 100; i++)
{
cts.Token.ThrowIfCancellationRequested();
System.Threading.Thread.Sleep(100);
Console.WriteLine($"Progress: {i}%");
}
});
// Отмена через 2 секунды
_ = Task.Delay(2000).ContinueWith(_ => cts.Cancel());
try
{
await task;
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation cancelled");
}
}
Пример 4: Обработка ошибок
public async Task ErrorHandling()
{
var factory = new TaskFactory();
var task = factory.StartNew(() =>
{
throw new InvalidOperationException("Something went wrong");
});
try
{
await task;
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
Task.Factory shortcut
Вместо создания нового TaskFactory, можно использовать статический Task.Factory:
// Это одно и то же
var factory1 = new TaskFactory();
var factory2 = Task.Factory;
// Task.Factory - это синглтон по умолчанию
var task = Task.Factory.StartNew(() => DoWork());
var continued = Task.Factory.ContinueWhenAll(/* ... */);
Когда использовать TaskFactory
✅ Используй TaskFactory, если:
- Нужен контроль над TaskCreationOptions
- Нужны ContinueWhen* методы
- Нужно использовать кастомный TaskScheduler
- Нужна гибкость в управлении Task'ами
❌ Используй Task.Run, если:
- Простой случай - просто запустить асинхронный код
- Работаешь с async/await
- Не нужны продвинутые опции
// Пример: Когда выбрать что-то
// Task.Run - простой случай
var result = await Task.Run(() => CalculateSomething());
// TaskFactory - сложный случай с зависимостями
var factory = new TaskFactory();
var task1 = factory.StartNew(() => FetchData());
var task2 = factory.StartNew(() => ProcessData());
var combined = factory.ContinueWhenAll(
new[] { task1, task2 },
tasks => CombineResults(tasks)
);
Заключение
TaskFactory - это мощный инструмент для создания и управления асинхронными операциями в .NET. Основные возможности:
- StartNew - создание и запуск Task
- ContinueWith - выполнение после другого Task
- ContinueWhenAll - выполнение после всех Task'ов
- ContinueWhenAny - выполнение после первого Task
- Опции - контроль над планированием и поведением
Хотя в современном коде рекомендуется использовать async/await и Task.Run, TaskFactory остаётся полезным инструментом для сложных сценариев координации асинхронных операций.