一次又一次,我看到它说使用async- await不会创建任何额外的线程.这没有任何意义,因为计算机一次看起来只做一件事以上的唯一方法就是
因此,如果async- await这些都没有,那么它如何使应用程序响应?如果只有一个线程,则调用任何方法意味着在执行任何其他操作之前等待方法完成,并且该方法中的方法必须在继续之前等待结果,依此类推.
我试图了解如何在C#中等待异步工作,有一件事让我很困惑.我知道任何使用await关键字的方法都必须用async标记.我的理解是当一个带有await关键字的行被命中时,该行下面的代码不会被执行.启动异步操作以在await行中继续执行该语句,并将控制返回给可以继续执行的调用方法.
问题1:这个假设是正确的还是仍然执行await关键字下面的代码?
其次假设我调用了一个服务方法async,需要返回它的结果.return语句在await关键字下面.
问题2:在异步调用完成之后或之前,返回语句是什么时候命中的?
问题3:我想使用该服务调用的结果和异步操作不会导致我希望在返回结果时命中调用方法.我知道这可以使用Result属性来完成,这会使调用同步.但是,在数据库操作中使用异步是什么原因导致它们在大多数应用程序中实际占用80%的时间.
问题4:如何在数据库操作中使用异步?有可能并推荐?
问题5:在哪个场景中异步操作有用似乎每个api现在只是在没有理由的情况下进行异步操作?还是我错过了使用异步操作的意义?
我的意思是说api正在制造asyn方法而没有理由是因为方法必须返回一些东西并且直到计算得出它们如何返回所以在本质中这个调用仍然不会被阻塞,因为它将是无用的直到结果被退回?
在www.asp.net上阅读此博客文章和官方说明后:
HttpClient旨在实例化一次,并在应用程序的整个生命周期中重复使用.特别是在服务器应用程序中,为每个请求创建一个新的HttpClient实例将耗尽重负载下可用的套接字数量.这将导致SocketException错误.
我发现我们的代码在每次调用时都处理了HttpClient.我正在更新我们的代码,以便我们重用HttClient,但我关心的是我们的工具但不是线程安全的.
以下是新代码的当前草案:
对于单元测试,我们为HttpClient实现了一个包装器,消费者调用包装器:
public class HttpClientWrapper : IHttpClient
{
private readonly HttpClient _client;
public Uri BaseAddress
{
get
{
return _client.BaseAddress;
}
set
{
_client.BaseAddress = value;
}
}
public HttpRequestHeaders DefaultRequestHeaders
{
get
{
return _client.DefaultRequestHeaders;
}
}
public HttpClientWrapper()
{
_client = new HttpClient();
}
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, String userOrProcessName)
{
IUnityContainer container = UnityCommon.GetContainer();
ILogService logService = container.Resolve<ILogService>();
logService.Log(ApplicationLogTypes.Debug, JsonConvert.SerializeObject(request), userOrProcessName);
return _client.SendAsync(request);
}
#region IDisposable Support
private …Run Code Online (Sandbox Code Playgroud) 我最近讨论了async-await如何工作,我想知道我是否正确.
async-await是否通过将线程的ESP堆栈指针切换为指向不同的堆栈帧来工作?这类似于WINAPI光纤或旧的Win3.1协作式多任务处理.
例如,考虑以下代码:
int Foo() {
int y = ReadSomethingFromConsole();
int x = await DoSomethingAsync();
return x+y;
}
Run Code Online (Sandbox Code Playgroud)
调用堆栈看起来像这样:
EventLoop(...);
.......
Foo();
Run Code Online (Sandbox Code Playgroud)
在我们到达该await语句时,计划在线程池中运行一个新任务,并await立即将ESP指针切换为指向我们所在EventLoop()函数的新堆栈帧.不会丢弃当前堆栈帧的内存段,只是ESP不再指向它.
然后事件循环运行更多事件,直到通知任务完成.此时,ESP切换到指向Foo()功能的堆栈段.
我是否理解正确,这是如何工作的?
编辑:新的堆栈框架是如何创建的await?是否复制了一些"模板"堆栈帧快照,类似于VM快照?
最好的做法是收集async循环内集合中的所有调用并执行Task.WhenAll().但是,想要了解await在循环中遇到的情况会发生什么,返回Task包含什么?那些进一步的async电话呢?它会创建新任务并将它们添加到已经返回的Task顺序中吗?
根据下面的代码
private void CallLoopAsync()
{
var loopReturnedTask = LoopAsync();
}
private async Task LoopAsync()
{
int count = 0;
while(count < 5)
{
await SomeNetworkCallAsync();
count++;
}
}
Run Code Online (Sandbox Code Playgroud)
我假设的步骤是
LoopAsync 被叫count 设置为零,代码进入while循环,条件被检查SomeNetworkCallAsync 被调用,等待返回的任务CallLoopAsync()现在,如果有足够的时间让流程生存,那么下一个代码行将如何/以何种方式执行count++并进一步SomeNetworkCallAsync执行?
更新 - 基于Jon Hanna和Stephen Cleary:
因此,有一个任务,该任务的实现将涉及5次对NetworkCallAsync的调用,但使用状态机意味着这些任务不需要明确地链接以使其工作.例如,这允许它根据任务的结果决定是否中断循环,等等.
虽然它们没有链接,但每次调用都会等待前一个调用完成,因为我们已经使用了await(在状态m/c中awaiter.GetResult();).它的行为就好像连续五年已吁请他们执行一前一后另一个(仅后,以前的呼叫被完成).如果这是真的,我们必须更加小心我们如何组成异步调用.对于ex:
而不是写作
private async Task …Run Code Online (Sandbox Code Playgroud) 据我所知,UI应用程序有一个主线程,其循环等效于
while(true)
{
var e = events.Dequeue(); // get event from the queue
e(); // run event
}
Run Code Online (Sandbox Code Playgroud)
我感到困惑的e()将是"畅通",如果它是在顶部async- await链.让我们说e()最终要求
public async Task WaitOneSecondAsync()
{
await Task.Delay(1000);
Console.WriteLine("Done waiting 1 second!");
}
Run Code Online (Sandbox Code Playgroud)
一旦主线程命中await Task.Delay(1000);它就不会"继续"到while循环的下一次迭代.所以你能解释一下这是如何解锁的吗?也许有代码示例?