我认为您在谈到 Dart 中的异步方法时错过了一些东西。
Dart 是单线程编程语言,Java 或 C# 是多线程编程语言,忘记了async
作为一个新线程,它不会发生在 Dart 中。
通常,您在 Dart 中所做的一切都将从 UI-Thread 开始。
在 Flutter 中,主 UI 线程用于渲染界面并响应用户输入。在此线程上运行繁重的计算或长时间运行的任务可能会导致应用程序体验不稳定,因为 UI 会被阻塞。为了解决这个问题,Dart 提供了异步编程功能,例如 async/await、Future 和 Isolates。
Async/await 是 Dart 中的构造,允许您编写非阻塞代码。当您将函数标记为异步时,表示该函数可以运行异步操作。在异步函数内,您可以在任何异步操作之前使用“await”关键字。此操作将返回一个 Future 对象,该对象表示未来某个时刻可用的潜在值。您也可以使用“then()”来实现相同的目的,但使用回调。
在同步语言中,您可能会这样:
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
您将在用户中收到大卫的数据,之后您将收到您的数据。这将阻止您正在执行的所有操作,直到结果准备就绪。这可能会导致冻结和性能问题。
在多线程语言中,您可以创建一个新线程,并将任务委托给它,这将在并发线程中执行(这不会发生在 dart 或 javascript 中,因为它们是单线程)。
如果您在 Dart 或 javascript 中执行此操作
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
// (Update note: when I wrote this answer dart still used "new",
// nowadays you don't need and shouldn't use it, in javascript yes.)
user 在 PersonalData 中将为 null,因为 fetch 事件是 Future。
在 Dart 中如何解决这个问题?
String user = await Database.fetch(David);
String personalData = await Database.fetch(user);
你已经告诉 dart 你要等待结果fetch
异步地。
您可以使用回调来实现相同的目的then
,虽然我个人不喜欢这样。
Database.fetch(David).then((user){
Database.fetch(user).then((personal){
String personalData = personal;
});
});
所以使用await会让dart像多线程语言一样表现出惊人的性能,对吗?错误的!!!!,即使 dart 异步运行它(这比阻塞同步更好),您仍然在主线程中运行它!如果您因繁重的任务而超载,您的 UI 仍然可能崩溃!
想象一下,您的数据库中有数十亿的数据,这项繁重的任务可能会导致屏幕上的动画冻结,并且您会在用户的 UI 中看到卡顿,为此目的发明了隔离。
Dart Isolates 为您提供了一种执行多线程类系统的方法。它们有自己独立的堆(内存),并在后台运行代码,类似于多线程语言的Thread。我可以解释隔离是如何工作的,但这会使这个响应变得很长,而且目标只是区分异步和多线程方法。
在 Flutter 中使用隔离来解决上述问题的一个简单方法是使用compute
.
创建计算是为了方便创建隔离,您只需传递函数和该函数将执行的数据,就是这样!
重要的是要记住计算是未来,所以你必须使用await
or then
得到它的结果。
在我们的示例中,我们可以创建一个新线程,并在完成时通过调用计算来获取其结果,如下所示:
String user = await compute(Database.fetch,David);
String personalData = await compute(Database.fetch,user);
很简单,不是吗?
总之:
在 Dart 中,所有等待一段时间才能完成的东西都被称为“Future”。
要等待将 future 的结果分配给变量,请使用await
or then
。
异步方法(await
and then
) 可用于从 Future 获取结果,并且在主线程上执行,因为 Dart 是单线程的。
如果你想在新线程上运行任何函数,你可以创建一个isolate。 Flutter 提供了一个易于使用的隔离包装器,称为compute
,你只需要传递一个将要处理的方法和将要处理的数据,它就会在将来返回它的结果。
- 注意:如果您要使用计算,请确保您使用的是静态或顶级方法(请参阅在我使用 Database.fetch 的示例中,如果您需要调用 Database().fetch 或需要创建,这并非偶然它的一个实例,意味着它不是静态方法,并且不能与隔离一起使用)。
好吧,如果 dart 提供了isolate,那么它不应该被认为是多线程的吗?
好吧,Dart 提供了一种使用隔离创建并发计算的方法,但需要注意的是,Dart 中的隔离与其他编程语言中的线程不同。
隔离 != 线程
在 Dart 中,每个隔离区都有自己的内存堆,隔离区之间的通信通过消息传递进行,这与传统多线程中使用的共享内存模型不同。这意味着隔离可以彼此独立运行并且不共享可变状态,这可以帮助避免多线程程序中可能出现的一些并发问题(当您想要在隔离之间共享状态时,有时可能会令人头痛) )
因此,虽然 Dart 可能不是严格意义上的多线程语言,但它确实提供了强大的并发模型,可以帮助您创建可扩展且高效的应用程序,但这并不能使其成为多线程语言,因为它实际上并不具有多线程,它具有多线程,尽管它们的行为方式可能相似,但也有其特殊性。
英语不是我的母语,但我希望我能帮助区分多线程异步编程和单线程异步编程。