执行异步I/O的旧.Net方式FileStream是使用FileStream.BeginRead()和FileStream.EndRead().
状态的MSDN文档FileStream.BeginRead():
FileStream提供两种不同的操作模式:同步I/O和异步I/O. 虽然可以使用其中任何一种,但底层操作系统资源可能仅允许以这些模式之一进行访问.
默认情况下,FileStream会同步打开操作系统句柄.在Windows中,这会降低异步方法的速度.如果使用异步方法,请使用FileStream(String,FileMode,FileAccess,FileShare,Int32,Boolean)构造函数.
在.Net 4.5x对执行异步I/O的方式FileStream是使用Stream.ReadAsync().
MSDN文档FileStream.ReadAsync()直接链接到文档的链接Stream.ReadAsync().本文档未提及在异步模式下打开文件的任何需要; 实际上,文档中的示例代码显然没有这样做.
因此,我假设在使用时File.ReadAsync()不需要以异步模式打开文件.
这个假设是否正确?
[编辑]
我刚刚发现了一篇关于使用Async for File Access的MSDN文章.
这表明:
本主题中的示例使用FileStream类,该类具有导致在操作系统级别发生异步I/O的选项.通过使用此选项,您可以避免在许多情况下阻止ThreadPool线程.
要启用此选项,请在构造函数调用中指定useAsync = true或options = FileOptions.Asynchronous参数.
所以,现在我在想,我应该可以打开该文件在异步模式......如果是这样,这是有点遗憾的是,在文档中提供的示例代码ReadAsync()并不能打开该文件异步!
我正在使用NetworkStream和TcpClient使用BeginRead异步接收数据.我需要对此操作应用超时,以便在指定的时间后读取将被中止.
据我所知,NetworkStream或TcpClient不支持 - 有一个ReceiveTimeout属性,但这似乎只适用于同步等效 - 'Read'.
甚至底层的Socket类似乎也不支持其BeginReceive方法中的超时.
我已经搜索过这个问题,我看到的唯一建议的解决方案是设置另一个后台线程来取消操作,如果它在超时期限内没有完成.这看起来像是一个可怕的黑客.当然有更好的方法吗?
我有一个Stream对象,我正在使用BeginRead开始(显然)读入缓冲区; 一旦读取完成,就会调用AsyncCallback函数.在这个函数中,我可以检查用户是否想要获取下一个"块"并再次启动BeginRead过程.
我遇到的问题是用户可能会选择在流仍在读取时取消(因此在调用AsyncCallback函数之前),那么如何取消流的读取?
只是为了进一步解释这个问题 - 如果我使用带有Streams Read方法或异步BeginRead方法的BackgroundWorker,我似乎会得到相同的结果.在我可以检查流是否应该停止读取之前,用户可以等待Read/BeginRead方法完成任何时间长度.
编辑:下面的代码应该可以完成这项任务,我距离C#中的任何一个距离都是一百万英里所以它可能会有一些错误,因为我怀疑它是完美的,尽管它确实展示了解决方案.
简而言之,CWorkManager管理一定数量的线程(保存在CWorkerDetail类中).每个CWorkerDetail都有一个状态,可以是EWaiting意味着工作人员可以启动,EReading意味着工作人员正在从源读取,在此期间工作人员可以立即停止,EWriting可以保存读取到磁盘的数据 - 这不能立即停止,这个过程必须在线程停止之前完成.最后是EAborting,由经理设定,如果工人应该尽快中止; 现在只有在工作者处于无法中断的事物(例如写入磁盘)的中间时才会设置此项.
现在,实际上没有任何读取或写入,因为这会使主要解决方案复杂化(这基本上只是StopWorker函数检查CWorker的标志,看它是否可以立即中止); 因此我们只是让线程睡觉.
GUI侧非常简单,只有一个列表框(显示每个工作人员的状态)和一个停止和启动按钮.所有代码都在下面,希望这有助于某些人,但正如我所说,我对C#并不擅长,所以请注意bug等...
CWorkManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ThreadApplication {
//A worker that spawns a number of threads (managed internally) that does nothing useful at all.
public class CWorkManager {
//The status of the worker.
public enum EWorkerStatus {
EWaiting,
EReading,
EWriting,
EAborting,
}
//Holds all data relevant to the worker.
private class CWorkerDetails {
//Simple variables.
private readonly Object _Lock=new Object(); …Run Code Online (Sandbox Code Playgroud) 我需要从我的虚拟 com 端口读取数据并检测消息“Dreq”。一旦我按下连接按钮,它就会连接到我的 COM8 端口并开始读取新线程。我还有一个断开连接按钮,我希望在其中关闭读数并断开与 COM8 端口的连接。但是,我在关闭 BeginRead 时遇到问题。
public partial class Form1 : Form
{
SerialPort sp;
Stream stream;
IAsyncResult recv_result;
private void button1_Click(object sender, EventArgs e)
{
sp = new SerialPort("COM8", 9600);
sp.Open();
sp.ReadTimeout = 50000;
sp.NewLine = "\n\r\0";
stream = sp.BaseStream;
recv_result = stream.BeginRead(new byte[1], 0, 0, new
AsyncCallback(ReadCallBack), stream);
}
private void ReadCallBack(IAsyncResult ar)
{
Stream stream = (Stream)ar.AsyncState;
string temp;
while (stream.CanRead)
{
temp = sp.ReadLine();
// ... do something with temp
}
}
private …Run Code Online (Sandbox Code Playgroud) 为什么使用 FileOptions.Asynchronous 创建 FileStream 会导致 FileStream.BeginRead 阻塞调用线程?
这是代码片段:
private static Task<int> ReadFileAsync(string filePath)
{
var file = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 64 * 1024, FileOptions.Asynchronous);
FileInfo fi = new FileInfo(filePath);
byte[] buffer = new byte[fi.Length];
Task<int> task = Task<int>.Factory.FromAsync(file.BeginRead, file.EndRead, buffer, 0, buffer.Length, null);
return task.ContinueWith(t =>
{
file.Close();
Console.WriteLine("Done ReadFileAsync, read " + t.Result + " bytes.");
return t.Result;
});
}
Run Code Online (Sandbox Code Playgroud)
当使用 JetBrains dotPeek 深入研究 MSFT FileStream 代码时,他们的代码中似乎存在一个错误:
if (!this._isAsync)
return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
else
return …Run Code Online (Sandbox Code Playgroud) 请原谅我对任务和异步的知识不足。
使用TcpClient类,我正在与可用服务器建立连接:
void async RunClientAsync()
{
TcpClient client = new TcpClient();
try
{
await client.ConnectAsync(IPAddress.Parse("1.1.1.1"), 8889);
Task.Start(() => ReadClientAsync(client));
}
catch (Exception ex)
{
HandleException(ex);
}
}
// -----
void async ReadClientAsync(TcpClient client)
{
byte[] bf = new byte[2048];
try
{
while(true)
{
int br = await client.NetworkStream().ReadAsync();
if (br > 0)
{
HandleInboundData(bf, br);
}
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
Run Code Online (Sandbox Code Playgroud)
辅助方法HandleException(Exception ex)和HandleInboundData(byte [] buffer,int length)将执行假定的任务。
与服务器的连接将是永久的,并且从服务器接收的数据的长度和频率将是未知的,其想法是将任务丢在那里,仅在数据可用时才接收和处理入站数据。
ReadClientAsync(TcpClient client)显然是失败的,因为如果没有可用数据,ReadAsync将始终返回0字节。
我应该如何使用异步/任务来编写ReadClientAsync来防止出现繁忙循环的情况?我以前在这些情况下使用BeginRead / EndRead,效果很好。在这种特殊情况下,这将是解决方案吗?
谢谢,
我有一个TCP网络程序,它通过连接发送已经序列化并编码到base64的大对象.我写了一个客户端库和一个服务器库,他们都使用NetworkStream's Begin/EndRead和Begin/EndWrite.这是我正在使用的代码(非常简化的版本):
对于服务器:
var Server = new TcpServer(/* network stuffs */);
Server.Connect();
Server.OnClientConnect += new ClientConnectEventHandler(Server_OnClientConnect);
void Server_OnClientConnect()
{
LargeObject obj = CalculateLotsOfBoringStuff();
Server.Write(obj.SerializeAndEncodeBase64());
}
Run Code Online (Sandbox Code Playgroud)
然后客户:
var Client = new TcpClient(/* more network stuffs */);
Client.Connect();
Client.OnMessageFromServer += new MessageEventHandler(Client_OnMessageFromServer);
void Client_OnMessageFromServer(MessageEventArgs mea)
{
DoSomethingWithLargeObject(mea.Data.DecodeBase64AndDeserialize());
}
Run Code Online (Sandbox Code Playgroud)
客户端库有一个回调方法,NetworkStream.BeginRead用于触发OnMessageFromServer将数据作为字符串传递的事件MessageEventArgs.
BeginRead/EndRead但是,当通过它接收大量数据时,它似乎在多个消息上分散.EG假装这是一条很长的信息:
"This is a really long message except not because it's for explanatory purposes."
Run Code Online (Sandbox Code Playgroud)
如果这确实是一个很长的消息,Client_OnMessageFromServer可能会被称为...说"三条消息"的碎片部分:
"This is a …Run Code Online (Sandbox Code Playgroud) 我知道通过使用Convert.To方法读取输入,但除此之外还有什么方法可以阅读.
int k = Convert.ToInt16(Console.ReadLine());
Run Code Online (Sandbox Code Playgroud) beginread ×8
c# ×7
asynchronous ×2
filestream ×2
stream ×2
tcpclient ×2
.net ×1
async-await ×1
beginreceive ×1
fragment ×1
input ×1
inputstream ×1