Asynchronous 如何使异步Dart调用同步?
我正在为一家德国公司评估Dart,方法是将各种Java程序移植到Dart,并对结果进行比较和分析。在浏览器中,Dart可以轻松获胜。对于服务器软件来说,性能似乎是一个严重的问题(请参阅),但这基本上被化解了 现在,我正在移植一些“简单”的命令行工具,我没有想到会有任何严重的问题,但至少有一个。有些工具确实发出HTTP请求以收集某些数据,而独立Dart虚拟机仅以异步方式支持这些请求。综观所有我能发现的,在一个主要是同步的软件中使用任何异步调用似乎都是不可能的 我知道我可以将可用的同步软件重组为异步软件。但这会将设计良好的软件转化为可读性较差、调试和维护难度较大的软件。对于某些软件来说,这根本没有意义。 我的问题:是否有一种(我忽略了)方法可以将异步调用嵌入到同步调用的方法中 我认为,提供一个仅在主线程内可用的系统调用并不困难,它只是将执行转移到整个队列异步函数调用列表中(不必先结束主线程),并且在最后一个被执行时返回并继续主线程 可能是这样的:Asynchronous 如何使异步Dart调用同步?,asynchronous,dart,synchronous,Asynchronous,Dart,Synchronous,我正在为一家德国公司评估Dart,方法是将各种Java程序移植到Dart,并对结果进行比较和分析。在浏览器中,Dart可以轻松获胜。对于服务器软件来说,性能似乎是一个严重的问题(请参阅),但这基本上被化解了 现在,我正在移植一些“简单”的命令行工具,我没有想到会有任何严重的问题,但至少有一个。有些工具确实发出HTTP请求以收集某些数据,而独立Dart虚拟机仅以异步方式支持这些请求。综观所有我能发现的,在一个主要是同步的软件中使用任何异步调用似乎都是不可能的 我知道我可以将可用的同步软件重组为异步
Future<bool> save() async {
// save changes async here
return true;
}
void saveClicked() {
saveButton.enabled = false;
save()
.then((success) => window.alert(success ? 'Saved' : 'Failed'))
.catchError((e) => window.alert(e))
.whenComplete(() { saveButton.enabled = true; });
}
Future<Null> saveClicked() async {
saveButton.enabled = false;
try {
bool success = await save();
window.alert(success ? 'Saved' : 'Failed');
}
catch (e) {
window.alert(e);
}
finally {
saveButton.enabled = true;
}
}
var synchFunction(){
var结果;
asyncFunction()。然后((){result=…;});
resync();//移动到并等待所有异步执行的系统调用
返回结果;
}
拥有这样的方法也会简化libapi。大多数“同步”呼叫都可以删除,因为重新同步呼叫可以完成此任务。这似乎是一个如此合乎逻辑的想法,我仍然认为它不知何故存在,但我错过了它。还是有一个严重的原因,为什么这不起作用?
在考虑了两天从
lm
(见下文)收到的答案后,我仍然不明白为什么不可能将异步Dart调用封装到同步Dart调用中。它总是在“正常”的同步编程环境中完成的。通常,您可以通过从异步例程获取“完成”或在超时后继续某个操作失败来等待重新同步
考虑到这一点,我的第一个建议可以这样加强:
var synchFunction(){
var结果;
异步函数()
.然后((){result=…;})
.whenComplete((){continueResync()});//完成消息
重新同步(超时);//以超时作为最大限制进行等待
//我们要么填写[result]到达这里,要么填写[TimeoutException]。
返回结果;
}
resync()
执行与结束隔离的main
方法后通常发生的相同操作,它开始执行排队的异步函数(或等待事件使其可执行)。一旦遇到continueResync()
调用,就会设置一个标志来停止此异步执行,并resync()
返回主线程。如果在给定的timeout
期间未遇到continueResync()
调用,它也会中止异步执行,并使用TimeoutException
离开resync()
对于某些受益于直接同步编程的软件组(不是客户端软件,也不是服务器软件),这样的功能将为必须处理仅异步库的编程人员解决许多问题
我相信我也为下面的
lm
论证中的主要论点找到了解决方案。因此,对于我提出的这个“增强”解决方案,我的问题仍然存在:是否有任何东西真的使Dart无法实现这一点?Dart本质上是异步的。试图避免异步是行不通的。
有些API调用有同步版本,例如在dart:io
中,在某些情况下使用它们似乎更简单,但因为没有所有方法/函数的同步版本,所以无法完全避免异步
随着最近推出的async
/await
功能,异步编程变得更加简单,代码看起来几乎像同步代码(但事实并非如此)
如果调用变为异步,它将保持异步。据我所知,您对此无能为力。在Dart的当前执行模型中无法实现
重新同步
功能
异步执行具有传染性。同步函数必须在执行任何其他异步事件之前返回,因此无法同步等待异步执行
Dart中的执行是单线程和基于事件的。resync
函数无法在不阻止同一隔离中所有其他执行的情况下阻止,因此挂起的异步操作永远不会发生
要阻止同步执行并继续执行其他操作,您需要将整个调用堆栈保留到该点,并在同步操作完成后将其恢复。如果您拥有该功能,那么可能有比Future和Stream更好的方法来做事情:)
此外,在基于事件的系统中,等待“所有异步执行”的定义并不明确。可能有广播流发出来自网络的事件、定期计时器或接收端口从另一个隔离区获取数据、或其他一些您无法等待的事件源,因为它们来自隔离区之外,或事件进程。当当前隔离关闭时,它可能会向另一个隔离发送一条最终关闭消息,因此实际上“异步执行”不会停止
final int number = waitFor<int>(someAsyncThatReturnsInt);
class StartConversationState extends State<StartConversationStatefulWidget> {
@override
Widget build(BuildContext context) {
_delayPush(); // this is the call that gets triggered multiple times
}
int lastKnownTime = 0;
int delayMillis = 3000;
_delayPush() async {
delayMillis += 1500;
await new Future.delayed(Duration(milliseconds: delayMillis));
int millisSinceEpoch = new DateTime.now().millisecondsSinceEpoch;
int delta = millisSinceEpoch - lastKnownTime;
// if delta is less than 10 seconds, means it was a subsequent interval
if (delta < 10000) {
print('_delayPush() , SKIPPING DUPLICATE CALL');
return;
}
// here is the logic you don't want to duplicate
// eg, insert DB record and navigate to next screen
}
import 'package:synchronized_lite/synchronized_lite.dart';
import 'dart:async';
// Using Lock as a mixin to further mimic Java-style synchronized blocks
class SomeActivity with Lock {
bool _started = false;
Future<bool> start() async {
// It's correct to return a Future returned by synchronized()
return synchronized(() async {
if(_started)
return false;
// perform the start operation
await Future.delayed(Duration(seconds: 1));
print("Started");
_started = true;
return true;
});
}
Future<void> stop() async {
// It's also correct to await a synchronized() call before returning
// It's incorrect to neither await a synchronized() call nor return its Future.
await synchronized(() async {
if(!_started)
return;
// perform the stop operation`enter code here`
await Future.delayed(Duration(seconds: 1));
print("Stopped");
_started = false;
});
}
}
// Prints:
// Started
// Stopped
main() async {
var a = SomeActivity();
print("Hello");
a.start();
a.start();
a.stop();
await a.stop();
}
Future<dynamic> lastCallFuture;
Future<T> myAsyncFunction<T>(T value) async {
if(lastCallFuture != null) {
await lastCallFuture;
}
return lastCallFuture = _myAsyncFunction(value);
}
Future<T> _myAsyncFunction<T>(T value) async => value;
Stock resultStockQueryByBarcodeAsync;
bool waitStockQueryByBarcodeAsyncCompleted = false;
Stock WaitStockQueryByBarcodeAsync(String barcode, int timeOut) {
CallStockQueryByBarcodeAsync(barcode);
var startTime = new DateTime.now();
while (!waitStockQueryByBarcodeAsyncCompleted) {
Duration difference = DateTime.now().difference(startTime);
if (difference.inMilliseconds > timeOut) {
throw TimeoutException("Timeout Exceeded");
}
//we must scope time. Because it can be enter endless loop.
}
return resultStockQueryByBarcodeAsync;
}
void CallStockQueryByBarcodeAsync(String barcode) async {
waitStockQueryByBarcodeAsyncCompleted = false;
resultStockQueryByBarcodeAsync = null;
var stock = await StockQueryByBarcodeAsync(barcode);/*your target async method*/
waitStockQueryByBarcodeAsyncCompleted = true;
resultStockQueryByBarcodeAsync = stock;
}
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
}));
}
Widget getRow(int i) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row ${widgets[i]["title"]}")
);
}
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
}