2017-09-22 115 views
1

流在我目前的代码,我有一个这样的方法来从设备读出的数据(伪代码):返回流立即然后写异步

public async Task<string> ReadAllDataFromDevice() 
{ 
    var buffer = ""; 
    using (var device = new Device()) 
    { 
     while(device.HasMoreData) 
     { 
      buffer += await device.ReadLineAsync(); 
     } 
    } 
    return buffer; 
} 

然后我想通过发送所有数据网络到一些接收器。数据量可能非常大。所以很显然,上述设计不是非常有效的内存,因为它需要读取所有数据,然后才能开始将其发送到网络套接字。

所以我想要的是一个返回流的函数。事情是这样的:

public async Task<Stream> ReadAllDataFromDevice() 
{ 
    var stream = new MemoryStream(); 
    using (var device = new Device()) 
    using (var streamWriter = new StreamWriter(stream, new UTF8Encoding(), 512, true)) 
    { 
     while(device.HasMoreData) 
     { 
      var line = await device.ReadLineAsync(); 
      await streamWriter.WriteLineAsync(line); 
     } 
     await streamWriter.FlushAsync(); 
    } 
    return stream; 
} 

这将返回一个流,但它显然并没有解决我的问题,因为只有在所有的数据已经从设备读取返回流。

于是我想出了这一点:

public Stream ReadAllDataFromDevice() 
{ 
    var stream = new MemoryStream(); 
    Task.Run(async() => { 
     using (var device = new Device()) 
     using (var streamWriter = new StreamWriter(stream, new UTF8Encoding(), 512, true)) 
     { 
      while(device.HasMoreData) 
      { 
       var line = await device.ReadLineAsync(); 
       await streamWriter.WriteLineAsync(line); 
      } 
      await streamWriter.FlushAsync(); 
     } 
    }); 
    return stream; 
} 

这是一个好的设计?我特别关心线程安全性,lambda中使用的流对象的生命周期以及异常处理。

或者是否有这种问题更好的模式?

编辑

其实我只是想出了另一种设计,看起来干净多了我。相反,具有ReadAllDataFromDevice()函数返回一个流,我让数据的消费者提供流,就像这样:

public async Task ReadAllDataFromDevice(Stream stream) 
{ 
    using (var device = new Device()) 
    using (var streamWriter = new StreamWriter(stream, new UTF8Encoding(), 512, true)) 
    { 
     while(device.HasMoreData) 
     { 
      var line = await device.ReadLineAsync(); 
      await streamWriter.WriteLineAsync(line); 
     } 
     await streamWriter.FlushAsync(); 
    } 
} 
+0

你怎么知道什么时候有没有被接收的数据量?这条线没有意义:device.HasMoreData。 – jdweng

回答

0

这是我现在使用的设计:

public async Task ReadAllDataFromDevice(Func<Stream, Task> readCallback) 
{ 
    using (var device = new Device()) 
    { 
     await device.Initialize(); 
     using (var stream = new DeviceStream(device)) 
     { 
      await readCallback(stream); 
     } 
    } 
} 

线逐行器件访问被封装在定制的DeviceStream类中(此处未显示)。

数据的消费者会是这个样子:

await ReadAllDataFromDevice(async stream => { 
    using (var streamReader(stream)) 
    { 
     var data = await streamReader.ReadToEndAsync(); 
     // do something with data 
    } 
});