Dart中的多线程
- Dart中多线程不仅仅是多线程,更像一个进程。拥有独立的内存空间,不存在资源抢夺的问题,因此也就没有了锁的概念了。
1.Isolate
- 异步任务中数据是隔离的
- 如果想要修改线程外数据,需要使用ReceivePort
- 监听,
port.listen((message) {})
- 调用后
senPort.send(data)
后,会回调listen
注意:此时listen回调后相当于添加一个主线程的异步任务。listen代码块任务,会最后执行
- 监听,
- 既然开辟了线程及端口,完成后就需要释放它
- 释放端口,
port.close()
- 释放线程对象
- 1.方法后面加上
async
- 2.Isolate创建的时候加上
await
,等待Isolate创建
注意:这里的await并不会阻塞主线程,因为Isolate开辟了子线程同时添加异步任务,这里的await是在子线程等待 - 3.在需要杀死时调用,
isolate.kill()
- 1.方法后面加上
//1.验证多线程
testIsolate() {
print('外部代码1');
Isolate.spawn(func, 10);
Isolate.spawn(func2, 10);
Isolate.spawn(func, 10);
Isolate.spawn(func2, 10);
Isolate.spawn(func, 10);
Isolate.spawn(func2, 10);
sleep(Duration(seconds: 2));
print('外部代码2');
}
//2.验证线程内和主线程下数据资源是不一样的
testIsolate2() {
print('外部代码1');
Isolate.spawn(func3, 100);
sleep(Duration(seconds: 2));
print('a = $a');
print('外部代码2');
}
//3.修改线程外数据,使用SendPort与port.listen配合使用
testIsolate3() async {
//创建一个port
ReceivePort port = ReceivePort();
print('外部代码1');
/*
* 这里的await并不会阻塞主线程,因为Isolate开辟了子线程同时添加异步任务,这里的await是在子线程等待。
* 这里使用await为了给Isolate赋值,等待创建好的Isolate对象,保证在listen调用时,可以拿到Isolate对象。
*/
Isolate isolate = await Isolate.spawn(func4, port.sendPort);
port.listen((message) {
//当sendPort发送数据后,会进入这个代码块,相当于在主线程添加了一个异步任务,因此在打印'外部代码2'后执行
a = message;
print('a修改为$a');
isolate.kill();
port.close();
});
//这里的sleep,为了验证当sendPort发送数据后,listen回调的代码块的执行顺序
// sleep(Duration(seconds: 2));
print('a = $a');
print('外部代码2');
}
func(int count) => print('1');
func2(int count) => print('2');
int a = 10;
func3(int count) {
a = count;
print('func3中a = $a');
}
func4(SendPort sendPort) {
sleep(Duration(seconds: 2));
sendPort.send(100);
print('send Completed');
}
2.compute
- 基于Isolate的封装
- 异步任务中数据也是隔离的,与
Isolate
一致 - 可以接收异步任务返回的数据。
注意:当接收返回的数据时,会阻塞主线程,因为返回值在主线程上接收的 - 当然,这里也可以用then接收返回值,保证线程不被阻塞。
注意:Isolate并不能使用该方式return返回值(传入的function无返回值,void),这是compute特有的封装(传入的function返回值为FutureOr<R>
)
testCompute() async {
print('外部代码1');
//这里的value在主线程上接收的,因此这里会阻塞主线程
int value = await compute(func5, 10);
print(value); //15
//异步任务中数据还是被隔离的,逻辑和Isolate一致。更改不了主线程下变量a的值
print(a); //10
print('外部代码2');
// flutter: 外部代码1
// flutter: count = 10
// flutter: 15
// flutter: 10
// flutter: 外部代码2
}
//当然,这里也可以用then接收返回值,保证线程不被阻塞
testCompute2() {
print('外部代码1');
compute(func5, 10).then((value) {
print(value);
//主线程下的变量a被隔离着的
print('a = $a');
});
print('外部代码2');
// flutter: 外部代码1
// flutter: 外部代码2
// flutter: count = 10
// flutter: 15
// flutter: a = 10
}
int a = 10;
int func5(int count) {
//尝试修改,查看是否影响线程外变量
a = 100;
print('count = $count');
return count + 5;
}
3.异步多线程
- 如何将一个异步任务,在子线程下执行
- 在Future代码块里返回
compute
//异步多线程
testAsyncThreads() {
Future(()=>compute(funcCompute,1)).then((value) => print('Future任务1-$value'));
Future(()=>compute(funcCompute,2)).then((value) => print('Future任务2-$value'));
Future(()=>compute(funcCompute,3)).then((value) => print('Future任务3-$value'));
Future(()=>compute(funcCompute,4)).then((value) => print('Future任务4-$value'));
// flutter: Future任务1-1
// flutter: Future任务4-4
// flutter: Future任务3-3
// flutter: Future任务2-2
}
funcCompute(int value)=>value;
此时,我们发现原本应该在事件队列中按顺序执行的任务,并发执行了
其实这里异步多线程的执行方式和多线程的执行方式一样
//多线程执行任务与异步多线程对比
testThreads() {
compute(funcCompute,1).then((value) => print('compute任务1-$value'));
compute(funcCompute,2).then((value) => print('compute任务2-$value'));
compute(funcCompute,3).then((value) => print('compute任务3-$value'));
compute(funcCompute,4).then((value) => print('compute任务4-$value'));
// flutter: compute任务4-4
// flutter: compute任务2-2
// flutter: compute任务1-1
// flutter: compute任务3-3
}
funcCompute(int value)=>value;
看到这里我们可以发现,异步完全没有必要,异步多线程其实就是多线程,在这里只是理解这一个概念。
网友评论