Flutter Dart中的批量期货

Flutter Dart中的批量期货,flutter,dart,future,batching,Flutter,Dart,Future,Batching,我希望将多个未来批处理到单个请求中,该请求在达到最大批处理大小时触发,或者在达到最早的未来收到后的最长时间后触发 动机 在Flatter中,我有许多UI元素,它们需要根据UI元素中的数据显示未来的结果 例如,我有一个用于某个地方的小部件和一个子小部件,它显示步行到某个地方需要多长时间。为了计算步行需要多长时间,我向GoogleMapsAPI发出了一个请求,以获取到达该地点的旅行时间 将所有这些API请求批处理为批处理API请求更高效、更经济。因此,如果Widget即时发出100个请求,那么fut

我希望将多个未来批处理到单个请求中,该请求在达到最大批处理大小时触发,或者在达到最早的未来收到后的最长时间后触发

动机

在Flatter中,我有许多UI元素,它们需要根据UI元素中的数据显示未来的结果

例如,我有一个用于某个地方的小部件和一个子小部件,它显示步行到某个地方需要多长时间。为了计算步行需要多长时间,我向GoogleMapsAPI发出了一个请求,以获取到达该地点的旅行时间

将所有这些API请求批处理为批处理API请求更高效、更经济。因此,如果Widget即时发出100个请求,那么futures可以通过单个提供者进行代理,该提供者将futures批处理成一个对Google的请求,并将Google的结果解包成所有单个请求

提供者需要知道何时停止等待更多的未来以及何时实际发出请求,这应该由最大“批处理”大小(即行程时间请求的大小)或您愿意等待批处理发生的最大时间量控制

所需的API类似于:


//客户机给出此消息是为了告诉提供者如何计算批处理结果。
抽象类批处理计算机{
未来计算(列出批量输入);
}
//批处理库返回具有此接口的对象
//这样客户端就可以将输入提交给批处理提供程序完成的。
抽象类BatchingFutureProvider{
未来提交(K输入值);
}
//如何在dart中实现此功能???
BatchingFutureProvider创建(
计算机,
int maxBatchSize,
持续时间maxWaitDuration,
);

Dart(或发布包)是否已经提供了此批处理功能,如果没有,您将如何实现上面的
create
功能?

这听起来非常合理,但也非常专业。 您需要一种表示查询的方法,将这些查询组合成单个超级查询,然后将超级结果拆分为单个结果,这就是
批处理计算机所做的。然后,您需要一个队列,在某些条件下可以刷新该队列

有一点很清楚,您需要使用
Completer
s来获得结果,因为在您拥有完成结果所需的价值或未来之前,当您想要返回未来时,总是需要使用它

我会选择的方法是:

import "dart:async";

/// A batch of requests to be handled together.
///
/// Collects [Request]s until the pending requests are flushed.
/// Requests can be flushed by calling [flush] or by configuring
/// the batch to automatically flush when reaching certain 
/// tresholds.
class BatchRequest<Request, Response> {
  final int _maxRequests;
  final Duration _maxDelay;
  final Future<List<Response>> Function(List<Request>) _compute;
  Timer _timeout;
  List<Request> _pendingRequests;
  List<Completer<Response>> _responseCompleters;

  /// Creates a batcher of [Request]s.
  ///
  /// Batches requests until calling [flush]. At that pont, the
  /// [batchCompute] function gets the list of pending requests,
  /// and it should respond with a list of [Response]s.
  /// The response to the a request in the argument list
  /// should be at the same index in the response list, 
  /// and as such, the response list must have the same number
  /// of responses as there were requests.
  ///
  /// If [maxRequestsPerBatch] is supplied, requests are automatically
  /// flushed whenever there are that many requests pending.
  ///
  /// If [maxDelay] is supplied, requests are automatically flushed 
  /// when the oldest request has been pending for that long. 
  /// As such, The [maxDelay] is not the maximal time before a request
  /// is answered, just how long sending the request may be delayed.
  BatchRequest(Future<List<Response>> Function(List<Request>) batchCompute,
               {int maxRequestsPerBatch, Duration maxDelay})
    : _compute = batchCompute,
      _maxRequests = maxRequestsPerBatch,
      _maxDelay = maxDelay;

  /// Add a request to the batch.
  ///
  /// The request is stored until the requests are flushed,
  /// then the returned future is completed with the result (or error)
  /// received from handling the requests.
  Future<Response> addRequest(Request request) {
    var completer = Completer<Response>();
    (_pendingRequests ??= []).add(request);
    (_responseCompleters ??= []).add(completer);
    if (_pendingRequests.length == _maxRequests) {
      _flush();
    } else if (_timeout == null && _maxDelay != null) {
      _timeout = Timer(_maxDelay, _flush);
    }
    return completer.future;
  }

  /// Flush any pending requests immediately.
  void flush() {
    _flush();
  }

  void _flush() {
    if (_pendingRequests == null) {
      assert(_timeout == null);
      assert(_responseCompleters == null);
      return;
    }
    if (_timeout != null) {
      _timeout.cancel();
      _timeout = null;
    }
    var requests = _pendingRequests;
    var completers = _responseCompleters;
    _pendingRequests = null;
    _responseCompleters = null;

    _compute(requests).then((List<Response> results) {
      if (results.length != completers.length) {
        throw StateError("Wrong number of results. "
           "Expected ${completers.length}, got ${results.length}");
      }
      for (int i = 0; i < results.length; i++) {
        completers[i].complete(results[i]);
      }
    }).catchError((error, stack) {
      for (var completer in completers) {
        completer.completeError(error, stack);
      }
    });
  }
}
导入“dart:async”;
///要一起处理的一批请求。
///
///收集[Request],直到清除挂起的请求。
///可以通过调用[flush]或通过配置来刷新请求
///当达到特定值时自动冲洗的批次
///特雷斯霍尔德。
类批处理请求{
最终int_最大请求;
最终持续时间_maxDelay;
最终未来函数(列表)\ u计算;
定时器超时;
列出待决请求;
列出响应完成者;
///创建[Request]的批处理程序。
///
///批处理请求,直到调用[flush]。在该端口上
///[batchCompute]函数获取挂起请求的列表,
///它应该用一个[响应]列表来响应。
///对参数列表中的请求的响应
///应位于响应列表中的同一索引,
///因此,响应列表必须具有相同的编号
///因为有请求,所以没有响应。
///
///如果提供了[maxRequestsPerBatch],则会自动删除请求
///每当有那么多请求挂起时刷新。
///
///如果提供了[maxDelay],则会自动刷新请求
///当最旧的请求已挂起那么长时间时。
///因此,[maxDelay]不是请求前的最长时间
///回答时,发送请求可能会延迟多长时间。
BatchRequest(未来函数(列表)batchCompute,
{int maxRequestsPerBatch,Duration maxDelay})
:_compute=batchCompute,
_maxRequests=maxRequestsPerBatch,
_maxDelay=maxDelay;
///向批处理添加请求。
///
///请求被存储,直到请求被刷新,
///然后,返回的future将完成并显示结果(或错误)
///从处理请求中收到。
未来添加请求(请求){
var completer=completer();
(_pendingRequests???=[])。添加(请求);
(_responseCompleters???=[])。添加(completer);
if(_pendingRequests.length=_maxRequests){
_冲洗();
}否则如果(_timeout==null&&u maxDelay!=null){
_超时=计时器(_maxDelay,_flush);
}
返回completer.future;
}
///立即刷新任何挂起的请求。
无效刷新(){
_冲洗();
}
void_flush(){
如果(_pendingRequests==null){
断言(_timeout==null);
断言(_responseCompleters==null);
回来
}
如果(_timeout!=null){
_超时。取消();
_超时=空;
}
var请求=_pendingRequests;
变量补足符=_响应补足符;
_pendingRequests=null;
_responseCompleters=null;
_计算(请求)。然后((列出结果){
if(results.length!=completers.length){
抛出StateError(“错误的结果数。”
“应为${completers.length},获得${results.length}”);
}
for(int i=0;i
您可以将其用作,例如:

void main() async {
  var b = BatchRequest<int, int>(_compute, 
      maxRequestsPerBatch: 5, maxDelay: Duration(seconds: 1));
  var sw = Stopwatch()..start();
  for (int i = 0; i < 8; i++) {
    b.addRequest(i).then((r) {
      print("${sw.elapsedMilliseconds.toString().padLeft(4)}: $i -> $r");
    });
  }
}
Future<List<int>> _compute(List<int> args) => 
    Future.value([for (var x in args) x + 1]);
void main()异步{
var b=批处理请求(_计算,
maxRequestsPerBatch:5,maxDelay:Duration(秒数:1));
var sw=秒表()…启动();
对于(int i=0;i<8;i++){
b、 addRequest(i)。然后((r){
打印(${sw.elapsedmillesons.toString().padLeft(4)}:$i->$r”);
});
}
}
未来