[英]Infinite Do…while loop using Async Await
I have following code: 我有以下代码:
public static async Task<string> ReadLineAsync(this Stream stream, Encoding encoding)
{
byte[] byteArray = null;
using (MemoryStream ms = new MemoryStream())
{
int bytesRead= 0;
do
{
byte[] buf = new byte[1024];
try
{
bytesRead = await stream.ReadAsync(buf, 0, 1024);
await ms.WriteAsync(buf, 0, bytesRead);
}
catch (Exception e)
{
Console.WriteLine(e.Message + e.StackTrace);
}
} while (stream.CanRead && bytesRead> 0);
byteArray = ms.ToArray();
return encoding.GetString(ms.ToArray());
}
I am trying to read Stream
to write into MemoryStream
asynchronously, but the Do...while
loop is failing to break. 我试图读取
Stream
以异步方式写入MemoryStream
,但Do...while
循环未能中断。 I mean it's an infinite loop. 我的意思是它是一个无限循环。 How to solve this?
怎么解决这个?
First, in an exceptional situation, your loop would continue indefinitely. 首先,在特殊情况下,您的循环将无限期地继续。 You shouldn't catch and ignore exceptions.
你不应该抓住并忽略异常。
Secondly, if the stream doesn't actually end , then bytesRead
would never be zero. 其次,如果流实际上没有结束 ,那么
bytesRead
永远不会为零。 I suspect this is the case because the name of the method ( ReadLineAsync
) doesn't imply to me that it will read until the end of the stream. 我怀疑是这种情况,因为方法的名称(
ReadLineAsync
)并不意味着它将在流结束之前读取。
PS CanRead
does not ever change for a specific stream. PS
CanRead
不会针对特定流进行更改。 It's whether it makes semantic sense for a stream to do a read operation, not whether it can read right now . 这是否使语义意义流做一个读操作,不在于它现在可以正确读取。
You have your loop condition set to run as long as CanRead is true and bytesRead is greater then 0. CanRead will always be true if your file is readable. 只要CanRead为true且bytesRead大于0,就将循环条件设置为运行。如果文件可读,CanRead将始终为true。 This means as long as you start reading your bytes will always be greater than zero.
这意味着只要您开始读取您的字节将始终大于零。 You need to have a maximum number of bytes to be read as well as a minimum or set some other control to break out.
您需要具有要读取的最大字节数以及最小值,或者设置一些其他控件才能突破。
I took your method and modified it just a tad by shortening the read buffer size and adding some debug statements 我采用你的方法并通过缩短读缓冲区大小并添加一些调试语句来修改它
public static async Task<string> ReadLineAsync(this Stream stream, Encoding encoding)
{
const int count = 2;
byte[] byteArray = Enumerable.Empty<byte>().ToArray();
using (MemoryStream ms = new MemoryStream())
{
int bytesRead = 0;
do
{
byte[] buf = new byte[count];
try
{
bytesRead = await stream.ReadAsync(buf, 0, count);
await ms.WriteAsync(buf, 0, bytesRead);
Console.WriteLine("{0:ffffff}:{1}:{2}",DateTime.Now, stream.CanRead, bytesRead);
}
catch (Exception e)
{
Console.WriteLine(e.Message + e.StackTrace);
}
} while (stream.CanRead && bytesRead > 0);
byteArray = ms.ToArray();
return encoding.GetString(byteArray);
}
}
but basically it worked as expected with the following call: 但基本上它通过以下调用按预期工作:
private static void Main(string[] args)
{
FileStream stream = File.OpenRead(@"C:\in.txt");
Encoding encoding = Encoding.GetEncoding(1252);
Task<string> result = stream.ReadLineAsync(encoding);
result.ContinueWith(o =>
{
Console.Write(o.Result);
stream.Dispose();
});
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
so I'm wondering could it be something with your input file? 所以我想知道它可能与你的输入文件有关吗? Mine was (encoded in Windows-1252 in Notepad++)
我是(在Notepad ++中用Windows-1252编码)
one
two
three
and my output was 我的输出是
Press ENTER to continue...
869993:True:2
875993:True:2
875993:True:2
875993:True:2
875993:True:2
875993:True:2
875993:True:2
875993:True:1
875993:True:0
one
two
three
note how the "Press ENTER to continue..." was printed first as expected because the main method was invoked asynchronously, and CanRead
is always true because it means the file is readable. 请注意如何按预期打印“按ENTER继续...”,因为主方法是异步调用的,并且
CanRead
始终为true,因为这意味着文件是可读的。 Its the state of how the file was opened, not the state meaning that the cursor is at the EOF. 它是文件打开方式的状态,而不是状态意味着光标位于EOF。
So, you are taking a stream from IMAP and this method is for converting that steam into text? 那么,你是从IMAP获取一个流,这个方法是将这个流转换为文本?
Why not construct a SteamReader round the stream and call either it's ReadToEndAsync or just ReadToEnd? 为什么不围绕流构建一个SteamReader并调用它的ReadToEndAsync或只调用ReadToEnd? I doubt the need for making this an Async operation, if the stream is something like an e-mail then it is unlikely to be so big that a user will notice the UI blocking while it reads.
我怀疑是否需要将其作为异步操作,如果流类似于电子邮件,那么用户在读取时会注意到UI阻塞的可能性不大。
If, as one of your comments suggests, this isn't a UI app at all then it is probably even less of an issue. 如果你的评论之一表明,这根本不是一个UI应用程序,那么它可能更不是一个问题。
If my assumptions are wrong then could I ask you to update your question with some more information about how this function is being used. 如果我的假设是错误的,那么我可以请求您更新您的问题,并提供有关如何使用此功能的更多信息。 The more information you can tell us, the better our answers can be.
您可以告诉我们的信息越多,我们的答案就越好。
EDIT: I just noticed that your method is called ReadLineAsync, although I can't see anywhere in the code that you are looking for a line ending. 编辑:我刚刚注意到你的方法被称为ReadLineAsync,虽然我无法在代码中看到你正在寻找行结尾的任何地方。 If your intention is to read a line of text then the SteamReader also provides ReadLine and ReadLineAsync.
如果您打算阅读一行文本,那么SteamReader还提供ReadLine和ReadLineAsync。
From my POV, looks like your code is trying to do the following: 从我的POV看起来,您的代码正在尝试执行以下操作:
MemoryStream
(which uses a byte array as its backing store), MemoryStream
(使用字节数组作为其后备存储), This seems...complicated to me. 这对我来说似乎很复杂。 Maybe I'm missing something, but to use
async
and await
, you've got to be using VS2012 and .Net 4.5, or VS2010. 也许我错过了一些东西,但是要使用
async
和await
,你必须使用VS2012和.Net 4.5或VS2010。 .Net 4.0 and the Async CTP, right? .Net 4.0和Async CTP,对吗? If so, why wouldn't you simply use a
StreamReader
and its StreamReader.ReadToEndAsync()
method? 如果是这样,为什么不简单地使用
StreamReader
及其StreamReader.ReadToEndAsync()
方法?
public static async Task<string> MyReadLineAsync(this Stream stream, Encoding encoding)
{
using ( StreamReader reader = new StreamReader( stream , encoding ) )
{
return await reader.ReadToEndAsync() ;
}
}
The overlapping i/o idea is nice, but the time required to write to a memory stream is, to say the least, not enough to make one whit of difference with respect to the time required to peform actual I/O (presumably your input stream is doing disk or network i/o). 重叠的i / o想法很不错,但是写入内存流所需的时间至少可以说是不足以在执行实际I / O所需的时间之间产生差异(可能是你输入的内容)流正在做磁盘或网络i / o)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.