Что такое многопоточность (multithreading)?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Многопоточность (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 выполняет:
- Весь синхронный код
- Microtasks
- 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),
],
);
}
}
Типичные сценарии многопоточности
| Задача | Решение |
|---|---|
| Парсинг JSON | compute(parseJson, data) |
| Шифрование данных | compute(encrypt, data) |
| Тяжелые вычисления | compute(calculate, input) |
| Чтение больших файлов | File().readAsStringSync() в isolate |
| Database queries | Async 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 мобильного приложения. Без правильного использования потоков любое сложное приложение будет зависать.