← Назад к вопросам

Что такое многопоточность (multithreading)?

1.2 Junior🔥 111 комментариев
#Архитектура Flutter

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Многопоточность (Multithreading)

Многопоточность — это способность программы выполнять несколько задач одновременно в разных потоках выполнения. В контексте Flutter и мобильной разработки это особенно важно для поддержания responsive UI.

Потокин в операционной системе

Поток (Thread) — это единица выполнения в программе. У каждого приложения есть:

  • UI Thread — выполняет UI операции и обработку жестов
  • Background Threads — выполняют тяжёлые операции

Если блокировать UI Thread, приложение зависает.

UI Thread в Flutter

// Плохо: блокируем UI Thread
void onButtonPress() {
  for (int i = 0; i < 1000000000; i++) {
    computeHeavyCalculation(); // Зависает на несколько секунд!
  }
  setState(() => result = newResult);
}

// Хорошо: выполняем в Background Thread
void onButtonPress() async {
  final result = await compute(heavyCalculation, data);
  setState(() => this.result = result);
}

Isolates в Dart

Isolate — это отдельный поток со своей памятью и event loop. Это Dart-специфичное понятие.

// Создание Isolate
import 'dart:isolate';

future<int> heavyCalculation(int n) {
  int sum = 0;
  for (int i = 0; i < n; i++) {
    sum += i;
  }
  return sum;
}

void main() async {
  // Выполняем в отдельном потоке
  final result = await compute(heavyCalculation, 1000000);
  print('Result: $result');
}

Функция compute()

compute() — это удобный способ запустить функцию в отдельном потоке:

import 'dart:isolate';

future<List<Data>> fetchAndParse() {
  return compute(parseJson, jsonString);
}

List<Data> parseJson(String json) {
  // Тяжёлый парсинг JSON здесь
  // Выполняется в background isolate
  return jsonDecode(json);
}

Ручное создание Isolate

Для более сложных случаев можно создавать Isolate вручную:

final receivePort = ReceivePort();
await Isolate.spawn(backgroundTask, receivePort.sendPort);

receivePort.listen((message) {
  print('Received: $message');
});

void backgroundTask(SendPort sendPort) {
  // Выполняется в отдельном потоке
  int sum = expensiveCalculation();
  sendPort.send(sum); // Отправляем результат
}

Event Loop vs Threads

Dart использует Event Loop, а не классическую многопоточность:

print('1. Start');

Future.microtask(() => print('2. Microtask'));
Future.delayed(Duration(seconds: 1), () => print('3. Delayed'));

print('4. Sync');

// Вывод:
// 1. Start
// 4. Sync
// 2. Microtask (высокий приоритет)
// 3. Delayed (после всех других операций)

UI Thread выполняет:

  1. Весь синхронный код
  2. Microtasks
  3. Macrotasks (I/O, callbacks)

Практический пример: Loading файла

class FileLoader extends StatefulWidget {
  @override
  State<FileLoader> createState() => _FileLoaderState();
}

class _FileLoaderState extends State<FileLoader> {
  String content = '';
  bool isLoading = false;

  void loadLargeFile() async {
    setState(() => isLoading = true);
    
    try {
      // Читаем файл в background потоке
      content = await compute(_readFile, filePath);
    } catch (e) {
      content = 'Error: $e';
    } finally {
      setState(() => isLoading = false);
    }
  }

  static String _readFile(String path) {
    // Это выполняется в background isolate
    // Может быть очень медленным без блокировки UI
    return File(path).readAsStringSync();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        if (isLoading) CircularProgressIndicator(),
        ElevatedButton(
          onPressed: loadLargeFile,
          child: Text('Load File'),
        ),
        if (content.isNotEmpty) Text(content),
      ],
    );
  }
}

Типичные сценарии многопоточности

ЗадачаРешение
Парсинг JSONcompute(parseJson, data)
Шифрование данныхcompute(encrypt, data)
Тяжелые вычисленияcompute(calculate, input)
Чтение больших файловFile().readAsStringSync() в isolate
Database queriesAsync repository методы
Сетевые запросыFuture с dio

Проблемы с многопоточностью

Race Conditions:

// Проблема: две операции одновременно
int counter = 0;

void increment() async {
  final temp = counter + 1;
  await Future.delayed(Duration(milliseconds: 100));
  counter = temp; // Может быть потеряно!
}

increment();
increment();
print(counter); // Ожидаем 2, получим 1!

Решение: используйте Mutex или synchronized:

import 'package:synchronized/synchronized.dart';

final _lock = Lock();
int counter = 0;

Future<void> increment() async {
  await _lock.synchronized(() async {
    final temp = counter + 1;
    await Future.delayed(Duration(milliseconds: 100));
    counter = temp;
  });
}

Deadlocks

// Плохо: взаимные ожидания между isolates
// Isolate A ждёт результат от Isolate B
// Isolate B ждёт результат от Isolate A
// → Deadlock!

// Решение: правильное управление зависимостями

Лучшие практики

  • Не блокируйте UI Thread — используйте compute() для тяжёлых операций
  • Используйте async/await — это проще чем Isolate вручную
  • Избегайте Race Conditions — используйте Lock/Synchronized
  • Тестируйте многопоточный код — может быть непредсказуемым
  • Профилируйте — DevTools покажет использование потоков

В контексте Flutter

class MyPage extends StatefulWidget {
  @override
  State<MyPage> createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  late Future<Data> dataFuture;

  @override
  void initState() {
    super.initState();
    // Запускаем в background
    dataFuture = _loadData();
  }

  Future<Data> _loadData() async {
    // Сетевой запрос (асинхронно)
    final response = await dio.get('/api/data');
    
    // Парсинг (в isolate)
    return compute(_parseData, response.data);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: dataFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        }
        return Text(snapshot.data.toString());
      },
    );
  }
}

Многопоточность — это основа responsive мобильного приложения. Без правильного использования потоков любое сложное приложение будет зависать.