陈航—Dart异步编程模式

前端狗

2019/07/09 发布于 编程 分类

GMTC2019 

文字内容
1. Event Loop、Future与Isolate - 单 线程模型下的Dart异步编程模式 陈航 美团点评⾼高级技术专家
2. 在此键⼊入姓名 在此键⼊入tittle
3. 在此键⼊入姓名 在此键⼊入tittle
4. ⾃自我介绍 曾就职于雅⻁虎北北研和新浪微博,2015年年加⼊入美团,经历了了外卖⽤用 户端和商家端发展的多个阶段,推动了了外卖移动端架构演进、线 上运维及终端技术栈融合等相关⼯工作。现任美团外卖商家业务终 端团队技术负责⼈人,致⼒力力于提升终端团队研发效率与交付质量量。 Wechat:hangisnice
5. 1.Dart单线程模型 ⽬目录 2.Event Loop - Dart代码运⾏行行模式本质 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 4.Isolate - Dart中的“多线程”机制 5.Future与Isolate适⽤用场景
6. 1.Dart单线程模型
7. Dart是单线程的 持续执⾏行行,不不允许抢占 ⽀支持异步(是的,单线程也可以异步)
8. 1.Dart单线程模型 持续执⾏行行,不不允许抢占 somebigLoop(){ for (int i = 0; i < 1000000; i++){ doSomethingSynchronously(); } }
9. 1.Dart单线程模型 ⽀支持异步 print(‘main start'); Timer(Duration(seconds:0),'>seconds:0), () => print('Timer 1')); Timer(Duration(milliseconds:10), () => print('Timer 2')); Timer(Duration(seconds:0),'>seconds:0), () => print('Timer 3')); print('main end'); main start main end Timer 1 Timer 3 Timer 2
10. 1.Dart单线程模型 Stack • 函数调⽤用上下⽂文信息 • 函数调⽤用链路路 Heap • 存放对象 • GC不不定期清理理 Queue • 异步事件回调(如Timer) Event Dispatcher • 另⼀一个平⾏行行世界 • 处理理完毕后回调⼊入队
11. 1.Dart单线程模型 执⾏行行示例例 b() run() { print("Adding code to the stack"); Timer(Duration(seconds:0), () { print('Anonymous function running next code from queue'); }); run Timer func b a b(y) { print("b() frame added to stack"); print("Value passed in is $y"); print("b() frame removed from stack"); } a(x) { print("a() frame added to stack"); b(x); print("a() frame removed from stack"); } a() func() run() Timer func a(42); print("Ending work for this stack"); }
12. 2.Event Loop - Dart代码运⾏行行模式本质
13. 为什什么单线程也可以异步? App绝⼤大多数时间都在等待 • 等待⽤用户交互 • 等待⽹网络请求返回 • 等待I/O结果 等待⾏行行为并不不是阻塞的 • 计算密集型操作在另⼀一个平⾏行行世界执⾏行行 • 事件回调告知状态
14. 2.Event Loop - Dart代码运⾏行行模式本质 Event Loop运⾏行行机制 同步任务在“主线程”执⾏行行 异步任务通过事件驱动“主线程”同步执⾏行行 不不断循环 简化版
15. 2.Event Loop - Dart代码运⾏行行模式本质 Event Queue与MicroTaskQueue eventLoopSingleShot(){ while (microTaskQueue.isNotEmpty){ Function microTaskItem = microTaskQueue.deque(); microTaskItem(); return; } if (eventQueue.isNotEmpty){ Function eventItem = eventQueue.deque(); eventItem(); } } 完整版
16. 2.Event Loop - Dart代码运⾏行行模式本质 Microtask Queue • 在控制流返回给Event Queue之前完成 • 接受来⾃自于Dart的事件 • scheduleMicroTask • 直接使⽤用的不不多(Flutter内部仅⽤用了了7处) • ⾼高优先级
17. 2.Event Loop - Dart代码运⾏行行模式本质 Event Queue • 接受来⾃自Dart外部和内部的事件 • • • I/O,⼿手势,绘制,定时器器,Dart Isolate消息等 Futures 低优先级 执⾏行行顺序:Main > Micro Task Queue> Event Queue
18. 3.单线程模型下的Dart代码是如何异步执⾏行行的?
19. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? Future • 对应⼀一个在未来某个时间点完成的异步任务 Future(() => print(‘Running in Future')); • 提供了了链式调⽤用的能⼒力力 Future(() => print(‘Running in Future')) .then((_) => print(‘and then')) .then((_) => print(‘and then’));
20. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 单个Future是如何异步执⾏行行的? • 函数执⾏行行体放⼊入Event Queue • 外部后续代码继续同步执⾏行行 • EventLoop按序取出Event,同步执⾏行行其相应链路路
21. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 多个Future是如何异步执⾏行行的? • 依照加⼊入Event Queue的先后顺序 Future(() => print(‘f1')); Future(() => print(‘f2’)); • then执⾏行行体在Future执⾏行行体完毕后⽴立即同步执⾏行行 Future(() => print(‘Future’)).then((_) => print(‘and then')); • 多个then⽅方法执⾏行行体按链式调⽤用有序执⾏行行 • 若Future执⾏行行体已经完毕,后续加⼊入的then执⾏行行体则放⼊入MicroTask Queue Future(() => print(‘f1')); Future(() => null).then((_) => print('then'));
22. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? f12 f11 f1 f10 f2 f3 f5 案例例分析 Future(() => print('f1')); Future fx = Future(() => null); Future(() => print('f2')).then((_) { print('f3'); scheduleMicrotask(() => print('f4')); }).then((_) => print('f5')); Future(() => print('f6')) .then((_) => Future(() => print('f7'))) .then((_) => print(‘f8')); Future(() => print('f9')); fx.then((_) => print('f10')); scheduleMicrotask(() => print('f11')); print(‘f12'); f1 null f2 f6 f11 f9 f4 f7 f10 Event Queue Microtask Queue f4 f6 f9 f7 f8
23. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 异步函数 • 对应⼀一个返回Future异步任务的函数 Future fetchContent() => Future.delayed(Duration(seconds:2), () => "Hello") .then((x) => "$x world"); ... print(fetchContent()); Instance of 'Future'
24. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 同步等待 • • 在调⽤用处使⽤用await关键字 在调⽤用处函数体声明使⽤用async关键字 Why? Future fetchContent() => Future.delayed(Duration(seconds:2), () => "Hello") .then((x) => "$x world"); main() async{ print(await fetchContent()); } Hello world
25. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 请记住 • async标记的函数并不不会并发执⾏行行 • await语句句也并不不会阻塞“主线程”执⾏行行 • Event Loop异步事件驱动他们同步执⾏行行
26. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 执⾏行行示例例 Future(() => print('f1')) .then((_) async => await Future(() => print('f2'))) .then((_) => print('f3')); Future(() => print('f4')); 换成scheduleMicrotask会怎么样? f1 f4 f2 f3 f1 f4 f2 await Event Queue
27. 3.Future - 单线程模型下的Dart代码是如何异步执⾏行行的? 执⾏行行示例例 Future fetchContent() => Future.delayed(Duration(seconds:2), () => "Hello") .then((x) => "$x world"); func() async => print(await fetchContent()); main() { print("main start"); func(); print("main end"); } main start main end Hello world await与async只对当前调⽤用上下⽂文的函数有效
28. 4. Isolate - Dart中的“多线程”机制
29. 为什什么说单线程已经⾜足够了了 APP⼤大多数时间处于静默期 不不存在资源抢占问题 很容易易实现并发 • I/O和⽹网络访问提供了了⾮非阻塞型API
30. 为什什么还需要多线程 CPU密集型任务使得APP卡顿 单线程⽆无法充分利利⽤用多核CPU 并发执⾏行行效率更更⾼高
31. 4. Isolate - Dart中的“多线程”机制 Isolate • Dart中的“多线程” • 独占资源,不不共享内存 • 有⾃自⼰己的Event Loop与Queue • 依靠消息机制进⾏行行通信
32. 4. Isolate - Dart中的“多线程”机制 Isolate • 拥有独⽴立函数⼊入⼝口 doSth(msg) => print(msg); 函数 如何实现消息通知? 参数 ⼊入⼝口 main() { ... Isolate.spawn(doSth, "Hello"); ... }
33. 4. Isolate - Dart中的“多线程”机制 Isolate • 拥有独⽴立函数⼊入⼝口 • 使⽤用SendPort进⾏行行单向通信 如何实现双向通信? Isolate isolate; start() async { ReceivePort receivePort= ReceivePort(); isolate = await Isolate.spawn(getMsg, receivePort.sendPort); receivePort.listen((data) { print('RECEIVE: $data'); receivePort.close(); isolate?.kill(priority: Isolate.immediate); isolate = null; }); } getMsg(sendPort) => sendPort.send("Hello");
34. 4. Isolate - Dart中的“多线程”机制 Isolate • 拥有独⽴立函数⼊入⼝口 • 使⽤用SendPort进⾏行行单向通信 • ⽀支持多个SendPort同时通信 • Isolate回传SendPort实现双向通信 太繁琐了了? Future asyncFactoriali(n) async{ final response = ReceivePort(); await Isolate.spawn(_isolate,response.sendPort); final sendPort = await response.first as SendPort; final answer = ReceivePort(); sendPort.send([n,answer.sendPort]); return answer.first; } _isolate(initialReplyTo) async { final port = ReceivePort(); initialReplyTo.send(port.sendPort); final message = await port.first as List; final data = message[0] as int; final send = message[1] as SendPort; send.send(syncFactorial(data)); } int syncFactorial(n) => n < 2 ? n : n * syncFactorial(n-1); main() async => print(await asyncFactoriali(4)); 并发计算阶乘
35. 4. Isolate - Dart中的“多线程”机制 Compute • Flutter对并发计算任务进⾏行行了了⼀一层封装 • 抽象了了Isolate的创建与SendPort的消息通信 int syncFactorial(n) => n < 2 ? n : n * syncFactorial(n-1); main() async => print(await compute(syncFactorial, 4));
36. 5.Future与Isolate适⽤用场景
37. Tips 不不可独⽴立运⾏行行的代码⽚片段 • 同步调⽤用 可独⽴立运⾏行行的代码⽚片段 • 不不影响性能:通过Event Loop驱动的Future异步任务 • • I/O,⽹网络请求,UI事件 影响性能:通过消息机制驱动的Isolate并发任务 • JSON解码、加密、图像处理理
38. 总结 Event Loop驱动主Isolate同步处理理异步事件 Future封装了了异步任务 异步任务通过await与async关键字,借助于Event Loop实现⾮非阻塞同步等 Isolate封装了了并发任务,有⾃自⼰己的Event Loop与Queue 并发任务通过SendPort进⾏行行单向通信(通过对⽅方Event Loop驱动)
39. 欢迎扫码(geektime123)备注“Flutter” 邀请你进我组建的“Flutter技术交流群”,⼀一起交流学习
40. 在此键⼊入姓名 在此键⼊入tittle
41. 在此键⼊入姓名 在此键⼊入tittle
42. THANKS THANKS! THANKS!