Ответ
Многопоточность — это техника выполнения нескольких потоков (threads) внутри одного процесса операционной системы для параллельного или псевдопараллельного решения задач. Каждый поток имеет свой собственный стек вызовов, но разделяет с другими потоками процесса общую память (кучу) и ресурсы (открытые файлы, сокеты).
Зачем это нужно?
- Повышение производительности (CPU-bound задачи): Использование нескольких ядер процессора для одновременных вычислений (например, обработка изображений, сложные расчёты).
- Отзывчивость приложений (UI): Выполнение длительных операций (загрузка файла, запрос к БД) в фоновом потоке, чтобы не блокировать главный поток интерфейса.
- Эффективное использование ресурсов (I/O-bound задачи): Пока один поток ожидает ответа от диска или сети, другие потоки могут продолжать работу.
Основные абстракции для работы с потоками в C# / .NET:
Thread(System.Threading): Низкоуровневая абстракция потока ОС. Прямое создание и управление сейчас используется реже из-за высоких накладных расходов.ThreadPool: Пул готовых к работе потоков, управляемый CLR. Эффективен для коротких задач. Не рекомендуется использовать для долгих блокирующих операций.Task/Task Parallel Library (TPL)(System.Threading.Tasks): Основная современная абстракция.Taskпредставляет собой асинхронную операцию, которая может выполняться в потоке из пула.// Запуск задачи в пуле потоков Task.Run(() => { Console.WriteLine($"Выполняюсь в потоке с ID: {Thread.CurrentThread.ManagedThreadId}"); // Длительная CPU-задача for (int i = 0; i < 10; i++) { Thread.Sleep(100); // Имитация работы Console.WriteLine(i); } });async/await: Ключевые слова для написания асинхронного кода, который легко читается как синхронный.awaitне блокирует поток, а освобождает его, пока выполняется асинхронная операция (например, I/O).public async Task<string> DownloadDataAsync(string url) { using var httpClient = new HttpClient(); // Поток освобождается здесь, пока идёт загрузка string data = await httpClient.GetStringAsync(url); // Продолжение выполнится на любом доступном потоке из пула return ProcessData(data); }Parallelкласс: Для простого параллельного выполнения циклов (For,ForEach) или операций (Invoke).Parallel.For(0, 100, i => { DoWork(i); // Метод будет вызван параллельно для разных i });
Критические проблемы и их решение:
- Гонка данных (Race Condition): Когда несколько потоков одновременно обращаются к общим данным и хотя бы один пишет. Решение: Использование примитивов синхронизации.
- Взаимная блокировка (Deadlock): Два или более потока бесконечно ждут друг друга. Решение: Упорядоченный захват блокировок, использование таймаутов (
Monitor.TryEnter). - Синхронизация: Для защиты общих ресурсов используются:
lock(ключевое слово, обёртка надMonitor).Mutex,Semaphore,SemaphoreSlim— для межпроцессной или более сложной синхронизации.Concurrentколлекции (ConcurrentBag<T>,ConcurrentDictionary<TKey,TValue>) — потокобезопасные коллекции.
| Поток (Thread) vs Задача (Task): | Аспект | Thread |
Task |
|---|---|---|---|
| Уровень | Низкий (поток ОС) | Высокий (работа над потоком) | |
| Ресурсы | Дорого (1 МБ стека) | Дёшево (работает через ThreadPool) |
|
| Управление | Ручное | Автоматическое (планировщик задач) | |
| Результат | Нет встроенного | Возвращает результат (Task<T>) |
|
| Отмена | Сложная | Встроенная (CancellationToken) |
|
| Современный подход | Редко | Рекомендуется |
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶