代码之家  ›  专栏  ›  技术社区  ›  Renato

如果未立即完成等待,则Dart File.writeAsString()方法不会写入文件

  •  0
  • Renato  · 技术社区  · 6 年前

    final File file = File("result.csv");
    
    Future send(String message) async {
      try {
        await file.writeAsString(message + '\n',
            mode: FileMode.append, flush: true);
      } catch (e) {
        print("Error: $e");
      }
      return await file.length();
    }
    
    main() async {
      final futures = <Future>[];
      for (int i = 0; i < 100; i++) {
        futures.add(send("$i"));
      }
      for (int i = 0; i < 100; i++) {
        print(await futures[i]);
      }
    }
    

    我希望每次打电话给 await futures[i] 在第二个循环中返回。然而,这似乎并没有发生。

    文件应包含0到99之间每个索引的一行。但它包含一行 99 后面是空行。第二个循环中的print调用总是打印相同的文件长度, 3 .

    事件循环似乎以某种方式合并了调用,并且只实际执行了最后一个调用,尽管我在第二个循环中仍然得到了100个不同的未来。

    为什么会发生这种情况,我怎样才能让期货在没有立即等待的情况下运行(我真的只需要等到稍后,当所有的电话 send 已经做了吗?

    0 回复  |  直到 6 年前
        1
  •  1
  •   attdona    6 年前

    使用循环:

    for (int i = 0; i < 100; i++) {
      futures.add(send("$i"));
    }
    

    倍数 send 被立即调用,每个并发打开并在文件中写入一个字符串:您有一个竞争条件,在最后,只会有一条消息被写入文件。

    使用返回未来的函数列表

    有了闭包,就可以实现文件访问的序列化版本,从而避免竞争条件。

    如果在循环中调用并等待这些函数,则会按顺序访问共享文件资源:

    import 'dart:io';
    
    final File file = File("result.csv");
    
    typedef Future SendFunction();
    
    Future send(String message) async {
      try {
        await file.writeAsString(message + '\n',
            mode: FileMode.append, flush: true);
      } catch (e) {
        print("Error: $e");
      }
      var l = await file.length();
      return l;
    }
    
    main() async {
    
      final futures = List<SendFunction>();
      //final futures = <Future>[];
    
      for (int i = 0; i < 100; i++) {
        //futures.add(send("$i"));
        futures.add(() => send("$i"));
      }
    
      for (int i = 0; i < 100; i++) {
        print(await futures[i]());
        //print(await futures[i]);
      }
    }
    

    同步包

    synchronized 提供锁机制以防止对异步代码的并发访问。

    在这种情况下,它可以用来避免对 result.csv

    import 'dart:io';
    import 'package:synchronized/synchronized.dart';
    
    final File file = File("result.csv");
    final lock = new Lock();
    
    Future send(String message) async {
      try {
        await file.writeAsString(message + '\n',
            mode: FileMode.append, flush: true);
      } catch (e) {
        print("Error: $e");
      }
      return await file.length();
    }
    
    main() async {
      final futures = <Future>[];
      for (int i = 0; i < 100; i++) {
        futures.add(lock.synchronized(() => send("$i")));
      }
      for (int i = 0; i < 100; i++) {
        print(await futures[i]);
      }
    }