一文详解Dart如何实现多任务并行

目录
  • Isolate(隔离区域)
  • async/await
  • Stream
  • Compute Function

Isolate(隔离区域)

Dart 是一种支持多任务并行的编程语言,它提供了多种机制来实现并发和并行。下面是 Dart 实现多任务并行的几种方式:

Dart 中的 Isolate 是一种轻量级的并发机制,类似于线程。每个隔离区域都是独立的内存空间,每个隔离区域都有自己的内存空间和执行线程,因此不同的隔离区域之间可以独立地执行代码,每个隔离区都在自己的核心上运行,不会阻塞其他 Isolate。从而实现并发。但是有一点需要注意它们之间不能直接共享数据,必须通过消息传递来实现。

下面是一个简单的示例代码,展示了如何使用Isolate在Dart中实现并发执行:

import 'dart:isolate';
void main() async {
  // 创建两个隔离区域
  final isolate1 = await Isolate.spawn(runIsolate, 1);
  final isolate2 = await Isolate.spawn(runIsolate, 2);
  // 等待隔离区域执行完毕
  await Future.wait([isolate1.exitCode, isolate2.exitCode]);
}
void runIsolate(int id) {
  // 隔离区域中执行的代码
  print('Isolate $id is running');
}

在上面的示例中,我们首先使用Isolate.spawn函数创建两个隔离区域,每个隔离区域都会执行runIsolate函数,并传入不同的参数(1和2)。runIsolate函数是隔离区域中实际执行的代码,它只是简单地打印一条信息。

在创建完隔离区域之后,我们使用Future.wait函数等待隔离区域执行完毕。这里的exitCode属性返回隔离区域的退出代码,如果代码成功执行,它将返回0。

当我们运行上面的代码时,我们会看到如下输出:

Isolate 1 is running
Isolate 2 is running

可以看到,两个隔离区域几乎同时启动并执行,实现了并发执行的效果。这只是Isolate的简单示例,您可以使用它来执行更复杂的并发任务,例如使用多个Isolate同时下载多个文件,或在不同的隔离区域中执行计算密集型任务,以提高性能等。

async/await

在Dart中,async/await使用的是Future对象来实现异步操作。当我们在一个函数或方法前面加上async关键字时,这个函数就变成了一个异步函数。在异步函数中使用await关键字可以等待其他异步操作的结果,而不会阻塞当前函数的执行。

下面是一个使用async/await实现异步并发的Demo代码,它会同时下载两个URL的内容,并在两个下载操作都完成后将结果打印出来:

import 'dart:async';
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
  final url1 = 'https://www.example.com';
  final url2 = 'https://www.example.net';
  final result1 = downloadUrl(url1);
  final result2 = downloadUrl(url2);
  final results = await Future.wait([result1, result2]);
  for (final result in results) {
    print(result);
  }
}
Future<String> downloadUrl(String url) async {
  final httpClient = HttpClient();
  final request = await httpClient.getUrl(Uri.parse(url));
  final response = await request.close();
  final contents = await response.transform(utf8.decoder).join();
  httpClient.close();
  return contents;
}

在上面的代码中,downloadUrl方法是一个异步函数,它使用HttpClient类下载给定URL的内容。在main函数中,我们使用Future.wait方法来等待两个下载操作都完成,然后打印结果。由于result1和result2是同时进行的,因此整个过程是并发的。

Stream

Dart 中的 Stream 是一种基于事件的异步编程模型,它可以处理连续的异步事件流。使用 Stream 可以将一个长时间运行的任务分解成多个小任务,并且可以在每个小任务完成后将结果推送到事件流中,这样其他任务就可以异步地获取结果。

下面是一个使用Stream实现异步并发的Demo代码,它会从两个URL下载数据并将结果打印出来:

import 'dart:async';
import 'dart:convert';
import 'dart:io';
Future<void> main() async {
  final url1 = 'https://www.example.com';
  final url2 = 'https://www.example.net';
  final stream1 = downloadUrl(url1);
  final stream2 = downloadUrl(url2);
  await for (final result in StreamGroup.merge([stream1, stream2])) {
    print(result);
  }
}
Stream<String> downloadUrl(String url) async* {
  final httpClient = HttpClient();
  final request = await httpClient.getUrl(Uri.parse(url));
  final response = await request.close();
  await for (final chunk in response.transform(utf8.decoder)) {
    yield chunk;
  }
  httpClient.close();
}

在上面的代码中,downloadUrl方法返回一个Stream对象,用于异步下载给定URL的内容。在main函数中,我们使用StreamGroup.merge方法将两个下载流合并为一个,并使用await for循环逐个处理下载结果。

需要注意的是,在downloadUrl方法中,我们使用yield关键字来逐个将下载的数据块发送到Stream中,这样就可以在下载过程中不断地将数据发送出去,而不用等到所有数据都下载完成后再一次性发送。这也是Stream在处理大量异步事件时的优势之一。

Compute Function

Dart 中的 Compute Function 是一种可以在独立的 Isolate 中运行的函数,它可以接收输入参数并返回结果。使用 Compute Function 可以将一个计算密集型的任务分解成多个小任务,在每个小任务中使用 Compute Function 来并行地计算结果,最终将结果合并起来。

下面是一个使用Compute Function实现异步并发的Demo代码,它会计算两个斐波那契数列,并将结果打印出来:

import 'dart:async';
import 'package:flutter/foundation.dart';
Future<void> main() async {
  final result1 = compute(fibonacci, 40);
  final result2 = compute(fibonacci, 41);
  final results = await Future.wait([result1, result2]);
  for (final result in results) {
    print(result);
  }
}
int fibonacci(int n) {
  if (n == 0) return 0;
  if (n == 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

在上面的代码中,我们使用compute函数将斐波那契数列的计算任务交给后台隔离线程执行,然后使用Future.wait方法等待两个任务都完成后打印结果。

需要注意的是,在使用compute函数时,传递给它的函数必须是顶层函数或静态函数,因为后台隔离线程无法访问非静态变量或实例变量。

总的来说,Dart 提供了多种机制来实现多任务并行,包括 Isolate、async/await、Stream 和 Compute Function。这些机制可以根据具体的任务需求选择使用,从而实现高效的并发和并行。

以上就是一文详解Dart如何实现多任务并行的详细内容,更多关于Dart 多任务并行的资料请关注我们其它相关文章!

(0)

相关推荐

  • Dart多态控制反转编码规范实例详解

    目录 前言 举栗子 方式一:通过传参构造器进行控制反转 方式二:通过继承 + 泛型进行解耦 前言 我们通常都知道程序设计要依赖抽象,提高复用性,做到对扩展开放,对修改关闭.贯彻SOLID五大原则的最重要法宝就是抽象和继承.多态是一种手段,下面,通过简单 demo 介绍 flutter 开发中常用的最佳实践. 举栗子 /// 不推荐,避免把逻辑放在公共底层处理 class TestWidget extends StatefulWidget { const TestWidget({Key? key}

  • Dart多个future队列完成加入顺序关系及原子性论证

    目录 引言 什么是 Future Future 操作具备'原子性'吗 实验写法一: 实验写法二: 实验写法三: 论证结论 引言 Dart 是一个在单线程中运行的程序.在程序中执行一个需要长时间的执行的操作,为避免卡住UI主线程,我们会用到异步(future),可以使程序在等待一个耗时操作完成时继续处理其他工作. 在进入正题之前,我们先了解一下 Dart 的消息循环机制: Dart 从两个队列执行任务:Event事件队列 和 Microtask微任务队列 事件循环会优先处理微任务队列,microt

  • SafeList in Flutter and Dart小技巧

    目录 正文 封装一个SafeList 测试一下 正文 最近遇到一些列表的错误,例如,列表为空时直接调用方法会报错. 一般都会在使用前判断列表是否为空,再使用. 虽然Flutter提供了Null safety,但是用的时候还是会忘记或者忽略,直接使用'!'来跳过非空判断. 封装一个SafeList 代码如下: class SafeList<T> extends ListBase<T> { final List<T> _list; final T defaultValue;

  • Flutter Dart快速排序算法示例详解

    目录 引言 快速排序算法 分治法(Divide and conquer) 快速排序算法实现 引言 在日常研发的过程中,我们无时无刻都在考虑自己开发的程序是否高效,一段好的程序执行离不开对算法的深刻认识和熟练掌握.接下来的日子,我将带着大家一起重温一下常见的几种算法. 先上大图: 下面我们一起来学习一下 快速排序算法 吧! 快速排序算法 维基百科介绍: 快速排序使用分治法(Divide and conquer)策略來把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列,最终合

  • Flutter入门学习Dart语言变量及基本使用概念

    目录 正文 变量 变量的声明赋值 变量的划分 默认值 变量的类型推断修饰符 Late变量 类型判断is和类型转换as 一些重要概念 空安全和可空类型? 表达式和语句 注释 DartPad 正文 Dart是Google发布的开源编程语言,是一种面向对象的语言.其主要应用是Flutter框架开发(Android.IOS),此外,也可以用在服务器.脚本.Web开发中.随着Flutter3.0开始支持全平台开发,Dart也可以实现桌面应用. 关于Dart的介绍不再细说.下面开始Dart的使用介绍 首先记

  • Dart语法之变量声明与数据类型实例详解

    目录 前言 1.安装与使用 1.1 安装 1.2 在 vscode 中使用 2.类型声明 2.1 变量声明 2.1.1 var 2.1.2 const 和 final 2.1.3 dynamic 和 Object 2.1.4 默认值 2.2 数据类型 2.2.1 Number 2.2.2 String 2.2.4 List 2.2.5 Set 2.2.6 Map 2.2.7 Runes(字符) 2.2.8 Symbols(符号) 2.2.9 枚举类型 前言 最近在学习做 flutter 移动端开

  • 一文详解Dart如何实现多任务并行

    目录 Isolate(隔离区域) async/await Stream Compute Function Isolate(隔离区域) Dart 是一种支持多任务并行的编程语言,它提供了多种机制来实现并发和并行.下面是 Dart 实现多任务并行的几种方式: Dart 中的 Isolate 是一种轻量级的并发机制,类似于线程.每个隔离区域都是独立的内存空间,每个隔离区域都有自己的内存空间和执行线程,因此不同的隔离区域之间可以独立地执行代码,每个隔离区都在自己的核心上运行,不会阻塞其他 Isolate

  • 一文详解 OpenGL ES 纹理颜色混合的方法

    目录 一.混合API 二.参数含义 2.1 举个栗子 2.2 参数含义 三. 几种常用混合方式效果 3.1 混合(GL_ONE, GL_ZERO) 3.2 混合(GL_ONE, GL_ONE) 3.3 混合(GL_ONE, GL_ONE_MINUS_DST_ALPHA) 3.4 混合 (GL_SRC_ALPHA, GL_ONE) 3.5 混合 (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 在OpenGL中绘制的时候,有时候想使新画的颜色和已经有的颜色按照一定的方式

  • 一文详解JS私有属性的6种实现方式

    目录 _prop Proxy Symbol WeakMap #prop ts private 总结 class 是创建对象的模版,由一系列属性和方法构成,用于表示对同一概念的数据和操作. 有的属性和方法是对外的,但也有的是只想内部用的,也就是私有的,那怎么实现私有属性和方法呢? 不知道大家会怎么实现,我梳理了下,我大概用过 6 种方式,我们分别来看一下: _prop 区分私有和公有最简单的方式就是加个下划线 _,从命名上来区分. 比如: class Dong { constructor() {

  • 一文详解JS中的事件循环机制

    目录 前言 1.JavaScript是单线程的 2.同步和异步 3.事件循环 前言 我们知道JavaScript 是单线程的编程语言,只能同一时间内做一件事,按顺序来处理事件,但是在遇到异步事件的时候,js线程并没有阻塞,还会继续执行,这又是为什么呢?本文来总结一下js 的事件循环机制. 1.JavaScript是单线程的 JavaScript 是一种单线程的编程语言,只有一个调用栈,决定了它在同一时间只能做一件事.在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行.在

  • 一文详解如何用原型链的方式实现JS继承

    目录 原型链是什么 通过构造函数创建实例对象 用原型链的方式实现继承 方法1:Object.create 方法2:直接修改 [[prototype]] 方法3:使用父类的实例 总结 今天讲一道经典的原型链面试题. 原型链是什么 JavaScript 中,每当创建一个对象,都会给这个对象提供一个内置对象 [[Prototype]] .这个对象就是原型对象,[[Prototype]] 的层层嵌套就形成了原型链. 当我们访问一个对象的属性时,如果自身没有,就会通过原型链向上追溯,找到第一个存在该属性原

  • 一文详解Java拦截器与过滤器的使用

    目录 流程图 拦截器vs过滤器 SpringMVC技术架构图 项目Demo 依赖 Interceptor拦截器 Filter过滤器 1.多Filter不指定过滤顺序 2.多Filter指定过滤顺序 流程图 拦截器vs过滤器 拦截器是SpringMVC的技术 过滤器的Servlet的技术 先过过滤器,过滤器过完才到DispatcherServlet: 拦截器归属于SpringMVC,只可能拦SpringMVC的东西: 拦截器说白了就是为了增强,可以在请求前进行增强,也可以在请求后进行增强,但是不一

  • 一文详解Vue如何整合Echarts实现可视化界面

    目录 一.什么是可视化 二.什么是Echarts 三.Echarts的优点 四.Vue 整合Echarts 下载Echarts依赖 Vue引入Echarts 测试使用Echarts 五.效果图 一.什么是可视化 可视化就是可以通过视觉进行传达的. 再专业一点就可以解释为可视化(Visualization)是利用计算机图形学和图像处理技术,将数据转换成图形或图像在屏幕上显示出来,再进行交互处理的理论.方法和技术. 将数据通俗的在屏幕中展现出来! 二.什么是Echarts 一个纯JavaScript

  • 一文详解Java中的类加载机制

    目录 一.前言 二.类加载的时机 2.1 类加载过程 2.2 什么时候类初始化 2.3 被动引用不会初始化 三.类加载的过程 3.1 加载 3.2 验证 3.3 准备 3.4 解析 3.5 初始化 四.父类和子类初始化过程中的执行顺序 五.类加载器 5.1 类与类加载器 5.2 双亲委派模型 5.3 破坏双亲委派模型 六.Java模块化系统 一.前言 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最 终形成可以被虚拟机直接使用的Java类型,这个过程

  • 一文详解Java线程的6种状态与生命周期

    目录 1.线程状态(生命周期) 2.操作线程状态 2.1.新创建状态(NEW) 2.2.可运行状态(RUNNABLE) 2.3.被阻塞状态(BLOCKED) 2.4.等待唤醒状态(WAITING) 2.5.计时等待状态(TIMED_WAITING) 2.6.终止(TERMINATED) 3.查看线程的6种状态 1.线程状态(生命周期) 一个线程在给定的时间点只能处于一种状态. 线程可以有如下6 种状态: New (新创建):未启动的线程: Runnable (可运行):可运行的线程,需要等待操作

  • 一文详解C++中运算符的使用

    目录 一.算术运算符 二.关系运算符 三.逻辑运算符 四.位运算符 五.赋值运算符 六.杂项运算符 一.算术运算符 运算符 描述 + 把两个操作数相加 - 从第一个操作数中减去第二个操作数 * 把两个操作数相乘 / 分子除以分母 % 取模运算符,整除后的余数 ++ 自增运算符,整数值增加 1 – 自减运算符,整数值减少 1 通过下面的例子可以让我们更好的理解C++中的运算符的意义与使用方法. #include <iostream> using namespace std; int main()

随机推荐