forEach() 循环的 Dart/Flutter 批处理?

Posted

技术标签:

【中文标题】forEach() 循环的 Dart/Flutter 批处理?【英文标题】:Dart/Flutter batching of a forEach() loop? 【发布时间】:2020-05-27 00:47:25 【问题描述】:

我有以下代码调用 API 以获取我的数据,然后解析结果。我的理解是 forEach 循环上的“异步”不是阻塞的,因此我使用输入 bool 来设置是否希望这些阻塞调用。

我现在的问题是,我在某些调用中遇到了“套接字:打开的文件太多”错误,大概是因为我在等待 API http 响应时遇到了太多的问题(让我知道您是否需要“tx”函数的更多详细信息)

所以我的问题是这样的。有没有一种快速的方法来限制下面的非阻塞“forEach”循环,并且可能在循环中每 5 次对 future.Delayed(Duration(milliseconds:250)) 执行一次等待?

当然,如果我只是计算并等待下面代码中的异步调用,我认为 forEach 循环将继续执行其余的循环。

我是否必须制作所有条目的临时列表并以非阻塞批次进行?

    if (makeBlocking) 
      for (var r in _commissionData[gwSerial].rooms.entries) 
        Map<String, dynamic> res = await _getSetupRoomDevicesApi.tx(
            _token, _clientId, gwSerialString, r.value.id);
        Map<String, dynamic> res2 = await _listCommissionAssociations.tx(
            _token, _clientId, gwSerialString, r.value.id);
        processCommissionData(r.value, res, res2);
      
     else 
      if (_commissionData != null) 
        _commissionData[gwSerial]?.rooms?.forEach((roomId, r) async 
          Map<String, dynamic> res = await _getSetupRoomDevicesApi.tx(
              _token, _clientId, gwSerialString, r.id);
          Map<String, dynamic> res2 = await _listCommissionAssociations.tx(
              _token, _clientId, gwSerialString, r.id);
          processCommissionData(r, res, res2);
        );
      
    

【问题讨论】:

是的,我想这是有道理的。 :) 今天看不到森林,因为有这么多树。 好的,我知道为什么我不只使用 for 循环。问题是 Map 是不可迭代的,除非你像我在上面的例子中那样抓住“.entities”。但在这种情况下,我不能在 for 循环体中添加“async”关键字。所以我不能轻易地使 for 循环既阻塞又非阻塞。 for 循环是阻塞的,foreach 是非阻塞的。 【参考方案1】:

好的,这就是我最终要做的。我创建了一个小函数,如果阻塞则可以等待,如果不阻塞则不等待。然后只需使用一个简单的 for 循环。

我遇到的问题是遍历地图,自然而然地使用“forEach”使其不会阻塞。但我想在那个非阻塞循环中每隔一段时间添加一个暂停(即油门)。但这意味着使用 for 循环,但我无法使 for 循环体“异步”。

也许我这样做仍然不是“最好”的方式,所以欢迎反馈:

  Future<void> syncGatewayRoomDeviceDetailData(
      int gwSerial, bool makeBlocking) async 
    if (_clientId == 0) 
      setState(() 
        _lastCommissionRoomUpdate = DateTime.now();
      );
     else 
      if (DateTime.now().difference(_lastCommissionRoomUpdate).inMilliseconds >
          -1) 
        print("Sync Gateway:$gwSerial blocking:$makeBlocking");
        _lastCommissionRoomUpdate = DateTime.now();
        String gwSerialString =
            gwSerial.toRadixString(16).padLeft(8, '0').toUpperCase();

        if (makeBlocking) 
          for (var r in _commissionData[gwSerial].rooms.entries) 
            await getAndProcessCommissionData(r, gwSerialString);
          
         else 
          // Even if not blocking, still need to throttle
          var throttleCount = 0;
          for (var r in _commissionData[gwSerial].rooms.entries) 
            if (++throttleCount % 9 == 0) 
              await Future.delayed(Duration(milliseconds: 500));
            
            getAndProcessCommissionData(r, gwSerialString);
          
        
       else 
        print("sync delayed: $gwSerial ");
      
    
  

  Future<void> getAndProcessCommissionData(var r, String gwSerialString) async 
    Map<String, dynamic> res = await _getSetupRoomDevicesApi.tx(
        _token, _clientId, gwSerialString, r.value.id);
    Map<String, dynamic> res2 = await _listCommissionAssociations.tx(
        _token, _clientId, gwSerialString, r.value.id);
    processCommissionData(r.value, res, res2);
  

【讨论】:

以上是关于forEach() 循环的 Dart/Flutter 批处理?的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中将 forEach 循环转换为 Future.forEach 循环

foreach 循环中的 foreach 循环

foreach循环

为啥在foreach循环中不能修改值类型实例

详细讲解foreach循环的用法

<c:foreach>怎么改变循环次数