C# 理解C中的异步和等待#
我正在尝试学习异步,并在C#中等待。我有三个方法,当我尝试调用所有这三个方法时,我想知道异步调用在C#中是如何工作的 我应该在延迟5秒后同时获取所有三个方法,但是我的C# 理解C中的异步和等待#,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我正在尝试学习异步,并在C#中等待。我有三个方法,当我尝试调用所有这三个方法时,我想知道异步调用在C#中是如何工作的 我应该在延迟5秒后同时获取所有三个方法,但是我的Delay2()方法在Delay1()方法的5秒后被调用,而Delay3()方法在Delay2()方法的5秒后被调用 有人能帮我理解C#中异步方法的工作原理吗 更新1 Async和Await假定是异步的,那么为什么我的常规语句会停止执行呢 public async Task Print() {
Delay2()
方法在Delay1()
方法的5秒后被调用,而Delay3()
方法在Delay2()
方法的5秒后被调用
有人能帮我理解C#中异步方法的工作原理吗
更新1
Async和Await假定是异步的,那么为什么我的常规语句会停止执行呢
public async Task Print()
{
Console.WriteLine(await Delay1());
Console.WriteLine("this is regular flow");
}
异步不是并发的。每次调用wait都会阻止执行下面的代码,直到任务完成。在本例中,您可以通过将示例更改为如下所示来创建并发性
class Program
{
static void Main()
{
new Content().Print().Wait();
Console.Read();
}
}
class Content
{
public async Task<string> Delay1()
{
await Task.Delay(5000);
return "hello";
}
public async Task<string> Delay2()
{
await Task.Delay(5000);
return "hello";
}
public async Task<string> Delay3()
{
await Task.Delay(5000);
return "hello";
}
public async Task Print()
{
var tasks = new[] {Delay1(), Delay2(), Delay3()};
await Task.WhenAll(tasks);
foreach(var result in tasks.Select(x => x.Result))
{
Console.WriteLine(result);
}
}
}
类程序
{
静态void Main()
{
新内容().Print().Wait();
Console.Read();
}
}
课堂内容
{
公共异步任务延迟1()
{
等待任务。延迟(5000);
回复“你好”;
}
公共异步任务延迟2()
{
等待任务。延迟(5000);
回复“你好”;
}
公共异步任务延迟3()
{
等待任务。延迟(5000);
回复“你好”;
}
公共异步任务打印()
{
var tasks=new[]{Delay1(),Delay2(),Delay3()};
等待任务。何时(任务);
foreach(任务中的var结果。选择(x=>x.result))
{
控制台写入线(结果);
}
}
}
您可以独立启动三个任务,并将它们存储在集合中。然后,您可以调用
wait Task.whalll
来阻止执行,直到所有这些任务都完成。之后,您可以循环使用结果,并根据需要使用它们。异步/await语法允许编写比不使用更可读的模式。为了让你理解真正的意思,考虑你的片段改写如下:
class Content
{
public void Delay1(Action<string> callback)
{
//something which takes 5000ms
callback("hello");
}
public void Delay2(Action<string> callback)
{
//something which takes 5000ms
callback("hello");
}
public void Delay3(Action<string> callback)
{
//something which takes 5000ms
callback("hello");
}
public void Print(Action callback)
{
this.Delay1(x=> {
Console.WriteLine(x);
this.Delay2(y => {
Console.WriteLine(y);
this.Delay3(z=> {
Console.WriteLine(z);
callback();
});
});
});
}
}
课程内容
{
公共无效延迟1(操作回调)
{
//需要5000毫秒的东西
回拨(“你好”);
}
公共无效延迟2(操作回调)
{
//需要5000毫秒的东西
回拨(“你好”);
}
公共无效延迟3(操作回调)
{
//需要5000毫秒的东西
回拨(“你好”);
}
公共作废打印(操作回调)
{
这个.Delay1(x=>{
控制台写入线(x);
这个.Delay2(y=>{
控制台写入线(y);
这个.Delay3(z=>{
控制台写入线(z);
回调();
});
});
});
}
}
您不应该依赖于系统实际执行的操作(例如,在Task.Delay的情况下)。它可以将“延迟”中继到其他线程(线程池的队列),但它可能会以与调用方相同的方式执行作业
正如@Rob正确指出的,异步不是并发:代码是按顺序执行的
这只是为了让你明白:没什么了。当你调用wait时,你要求curret方法停止执行,直到“waitied”调用结束;所以,当你说:
Console.WriteLine(await Delay1());
您要求当前方法(打印)停止,直到Delay1()完成
为了获得预期的结果,必须在不使用await指令的情况下调用它们(使用await调用异步方法不是强制性的)
下面是一个例子:
public class Content
{
public async void Delay1()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public async void Delay2()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public async void Delay3()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public void Print()
{
Delay1();
Delay2();
Delay3();
}
}
编辑:正如@Adrian指出的,Print方法可能比三个Delay方法调用完成得更快。我在测试中没有注意到它,因为有一个控制台 引用更新 因为我的答案被否决的原因我不知道,因为否决的选民没有给出任何否决的理由,除了罗布,我在这里为我的答案辩护 这里的重点不是要证明任何人是错的,而是要确保OP收到正确的信息和事实 那么,问题是什么?我认为有两个问题:
Console.WriteLine(await Delay1());
public class Content
{
public async void Delay1()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public async void Delay2()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public async void Delay3()
{
await Task.Delay(5000);
Console.WriteLine("hello");
}
public void Print()
{
Delay1();
Delay2();
Delay3();
}
}
namespace TaskAsyncTests
{
using System.Threading.Tasks;
class Program
{
static async Task<KeyValuePair<string, long>> TaskThis(Func<string> fn)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
var task = Task.Run(fn); //fn will be 1sec
await Task.Delay(1000); //also being delayed 1sec here
var result = await task;
watch.Stop();
return new KeyValuePair<string, long>(result, watch.ElapsedMilliseconds); //result should only be approx. 1 sec though
}
static void Main(string[] args)
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
var results = Run(Task.WhenAll(new[]
{
TaskThis(LongProcessingFunction),
TaskThis(LongProcessingFunction),
TaskThis(LongProcessingFunction),
}));
watch.Stop();
foreach (KeyValuePair<string, long> item in results)
{
Console.WriteLine(@"result:= '{0}' ElapsedMilliseconds := {1}", item.Key, item.Value.ToString());
}
Console.WriteLine("total ElapsedMilliseconds := {0}", watch.ElapsedMilliseconds);
watch.Reset();
watch.Start();
var result = Run(GetSomethingAsync());
watch.Stop();
Console.WriteLine(@"result->PropertyOne := '{0}' ElapsedMilliseconds := {1}", result.PropertyOne.Key, result.PropertyOne.Value.ToString());
Console.WriteLine(@"result->PropertyTwo := '{0}' ElapsedMilliseconds := {1}", result.PropertyTwo.Key, result.PropertyTwo.Value.ToString());
Console.WriteLine(@"result->PropertyThree := '{0}' ElapsedMilliseconds := {1}", result.PropertyThree.Key, result.PropertyThree.Value.ToString());
Console.WriteLine("total ElapsedMilliseconds := {0}", watch.ElapsedMilliseconds);
Console.ReadLine();
}
static string LongProcessingFunction()
{
Task.Delay(1000).Wait();
return "Hello World";
}
static T Run<T>(Task<T> taskRunner)
{
return taskRunner.Result;
}
static T[] Run<T>(Task<T[]> taskRunner)
{
return taskRunner.Result;
}
static async Task<dynamic> GetSomethingAsync()
{
var resultsTask = Task.WhenAll(new[]
{
TaskThis(LongProcessingFunction),
TaskThis(LongProcessingFunction),
TaskThis(LongProcessingFunction)
}).ConfigureAwait(false);
// do other stuff here
Task.Delay(2000).Wait();
var results = await resultsTask;
return new
{
PropertyOne = results[0],
PropertyTwo = results[1],
PropertyThree = results[2]
};
}
}
}
result:= 'Hello World' ElapsedMilliseconds := 1025
result:= 'Hello World' ElapsedMilliseconds := 1014
result:= 'Hello World' ElapsedMilliseconds := 1014
total ElapsedMilliseconds := 1028
result->PropertyOne := 'Hello World' ElapsedMilliseconds := 1001
result->PropertyTwo := 'Hello World' ElapsedMilliseconds := 1001
result->PropertyThree := 'Hello World' ElapsedMilliseconds := 1000
total ElapsedMilliseconds := 2001