Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 理解异步-我可以等待同步方法吗?_C#_.net_Asynchronous_Io_Async Await - Fatal编程技术网

C# 理解异步-我可以等待同步方法吗?

C# 理解异步-我可以等待同步方法吗?,c#,.net,asynchronous,io,async-await,C#,.net,Asynchronous,Io,Async Await,试图理解C#中的async wait,可能有点陷入了“鸡和蛋”的问题 一个async方法是否需要调用另一个async以使其异步 作为一个高级示例,我正在尝试对文件系统进行一次简单的写操作,但不确定如何才能使此任务成为可以等待的任务(如果有的话) public Task<FileActionStatus> SaveAsync(path, data) { // Do some stuff, then... File.WriteAllBytes(path, data);

试图理解C#中的
async wait
,可能有点陷入了“鸡和蛋”的问题

一个
async
方法是否需要调用另一个
async
以使其异步

作为一个高级示例,我正在尝试对文件系统进行一次简单的写操作,但不确定如何才能使此任务成为可以等待的任务(如果有的话)

public Task<FileActionStatus> SaveAsync(path, data)
{
    // Do some stuff, then...

    File.WriteAllBytes(path, data); // <-- Allow this to yield control?

    // ... then return result
}
public Task SaveAsync(路径、数据)
{
//做点什么,然后。。。
File.writealBytes(路径、数据);//
异步方法是否需要调用另一个异步方法才能成为异步方法

通常情况下是这样的,因为async一直到调用堆栈的底部,并在实际执行IO操作的最低位置结束。在您的情况下,您使用的是
File.writealBytes
,这是一个阻塞同步调用。您无法神奇地将其变为异步

有人能用一个非常高级的例子来启发我如何以异步方式将文件写入文件系统吗

为此,您需要使用公开异步API的机制,例如:

public async Task SaveAsync(字符串路径,字节[]数据)
{
使用(FileStream sourceStream=new FileStream(path,
FileMode.Append、FileAccess.Write、FileShare.None、,
bufferSize:4096,UseAync:true)
{
等待sourceStream.WriteAsync(数据,0,数据.Length);
}
//返回一些结果。
}

除了Yuval answer:如果您的类没有任何异步方法,您可以在后台线程上运行该方法,方法是使用

public Task<FileActionStatus> SaveAsync(path, data)
{
  return Task.Run<FileActionStatus>(() =>
    {
      File.WriteAllBytes(path, data);
      // don't forget to return your FileActionStatus
    });
}
public Task SaveAsync(路径、数据)
{
返回任务。运行(()=>
{
File.writealBytes(路径、数据);
//别忘了返回您的FileActionStatus
});
}

更新:线程占用资源。请仔细考虑如何使用它们。同步操作的异步包装至少可以在UI响应性和并行性方面为您带来好处。在选择一种方案之前,请测试不同的方案。在其他情况下,请使用单线程。

请注意,尽管异步方法应该调用其他方案异步方法,这些其他方法可以是异步的,而无需使用
async
关键字来实现。例如,可以使用
Task.Factory.StartNew
ContinueWith
方法使用.NET 4.0样式来实现。您仍然可以使用
wait
异步等待完成此类异步方法。@YacoubMassad是的,但是使用
Task.Run
并不是一个自然的异步操作。如果你使用它,你只是使用了async-over-sync反模式,你并没有真正使用异步IO。@YuvalItzchakov,我同意,但我想说的是,你仍然可以使用异步方法,而不需要真正使用
async
关键字。例如,您可以有一个方法返回
任务
,并包装一些EAP操作(通过
TaskCompletionSource
)没有使用
async
关键字。@YacoubMassad好吧,使用
TaskCompletionSource
作为EAP的包装器与使用
Task.Run
是不同的。前者实际上只会包装一个带有等待的自然异步操作。@YuvalItzchakov,是的,但是OP询问
async
方法是否必须调用e> 仅限async
方法。我假设OP表示
async
关键字。在这种情况下,答案不应该是肯定的。那不是真的。你没有使用
任务生成异步操作。运行
。你只是在排队同步操作并在线程池线程上执行它。你实际上是适得其反,一个s async的意思是在执行IO时释放线程,而这正好相反。这叫做,我不鼓励任何人使用它。很抱歉,我的回答可能太笼统了。但是,在某些情况下,这种方法会带来很多好处,比如UI响应能力。处理大文件可能是移动将代码转换到另一个线程。顺便说一句,您在上面链接的博客中提到了这一点以及其他一些好处。@YuvalItzchakov这是库中的一种反模式,但它在UI应用程序和其他可能的情况中确实有它的位置。尽管真正的异步代码效率更高,但这种效率可能不值得增加复杂性@svick当然有它的位置。但是OP特别问了如何异步写入文件。虽然这是一个很好的答案,可以作为“如何在IO操作期间保持UI的响应性只有通过同步方法公开?”这不是问题的答案。而且,人们会错误地看待这样的答案并思考“好的,这就是异步的方式”。所以,若你们选择了这是一条路线,请确保你们解释了这条路线的含义。@svick我想我们对这个问题的解释是不同的:)。我通常不同意这样的回答:“你们仍然可以通过使用Task.Run自己生成它。”"。不,您不能通过使用
任务生成自然异步操作。运行
,而您可以使用它来保持UI的响应性,如果有问题的话。术语很重要。一个异步方法是否需要调用另一个异步方式才能使其异步?
-问题是向后的。我发现,我觉得这样更好方法是首先考虑操作(例如,编写文件),询问它是否自然异步(例如,如果同步实现,它会阻止线程),找到合适的异步API(例如,没有
writealBytesAsync
,但您可以自己创建),最后使调用方法
async
,这样它就可以使用
wait
@StephenCleary调用API了。这是一个很好的建议,也是一个很好的思考方法。谢谢!
public Task<FileActionStatus> SaveAsync(path, data)
{
  return Task.Run<FileActionStatus>(() =>
    {
      File.WriteAllBytes(path, data);
      // don't forget to return your FileActionStatus
    });
}