我正在学习async/await,并遇到了需要同步调用异步方法的情况.我怎样才能做到这一点?
异步方法:
public async Task<Customers> GetCustomers()
{
return await Service.GetCustomersAsync();
}
Run Code Online (Sandbox Code Playgroud)
正常使用:
public async void GetCustomers()
{
customerList = await GetCustomers();
}
Run Code Online (Sandbox Code Playgroud)
我尝试过使用以下内容:
Task<Customer> task = GetCustomers();
task.Wait()
Task<Customer> task = GetCustomers();
task.RunSynchronously();
Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)
Run Code Online (Sandbox Code Playgroud)
我也从这里尝试了一个建议,但是当调度程序处于暂停状态时它不起作用.
public static void WaitWithPumping(this Task task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
Run Code Online (Sandbox Code Playgroud)
以下是调用的异常和堆栈跟踪RunSynchronously:
System.InvalidOperationException
消息:可能无法在未绑定到委托的任务上调用RunSynchronously.
InnerException:null
资料来源:mscorlib …
我想问你关于正确架构何时使用的意见Task.Run.我在WPF .NET 4.5应用程序(使用Caliburn Micro框架)中遇到了滞后的UI.
基本上我在做(非常简化的代码片段):
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
从我阅读/看到的文章/视频中,我知道await async不一定在后台线程上运行,并且需要在后台开始工作,需要等待它Task.Run(async () => …
我有一个async方法:
public async Task<string> GenerateCodeAsync()
{
string code = await GenerateCodeService.GenerateCodeAsync();
return code;
}
Run Code Online (Sandbox Code Playgroud)
我需要从同步方法中调用此方法.
如何在不必复制GenerateCodeAsync方法的情况下执行此操作以使其同步工作?
更新
然而找不到合理的解决方案
但是,我看到HttpClient已经实现了这种模式
using (HttpClient client = new HttpClient())
{
// async
HttpResponseMessage responseAsync = await client.GetAsync(url);
// sync
HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
Run Code Online (Sandbox Code Playgroud) 我试图async/await在我的Web API项目中使用ASP.NET 的功能.我不确定它是否会对我的Web API服务的性能产生任何影响.请在下面找到我的应用程序中的工作流程和示例代码.
工作流程:
UI应用程序→Web API端点(控制器)→Web API服务层中的调用方法→调用另一个外部Web服务.(这里我们有数据库交互等)
控制器:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
Run Code Online (Sandbox Code Playgroud)
服务层:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
Run Code Online (Sandbox Code Playgroud)
我测试了上面的代码并且正在运行.但我不确定它是否正确用法async/await.请分享你的想法.
我喜欢新的System.Net.Http.HttpClient类.它有一个很好的简单API,它不会抛出正常的错误.但它只是异步.
我需要代码(深入服务器内)
foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);
Run Code Online (Sandbox Code Playgroud)
经典的顺序同步代码.我看到了几个类似的问题,但实际上从未真正说过"做这个".我在看
client.PostAsync.Wait()
Run Code Online (Sandbox Code Playgroud)
世界尖叫'不要这样做'.怎么样:
client.PostAsync.Result()
Run Code Online (Sandbox Code Playgroud)
这不只是伪装等待?
最后,我最终传入一个处理结果的lambda回调,然后唤醒显式等待EventWaitHandle的调用线程.很多管道.有没有更简单的东西或者我只是回到使用旧的http客户端
编辑:进一步阅读后,我怀疑这段代码与Wait和Result有相同的问题,它只是一个更长的死锁
编辑:我有MS PM最近向我确认有一个任务'可能需要> X ms(我忘了X)的任何API必须是异步',许多PM将此解释为'仅异步'(不清楚这是什么旨在).因此Document DB api只是异步.
我在“正确的方法”周围使用了引号,因为我已经清楚地知道使用异步API的正确方法是简单地让异步行为在整个调用链中传播。这里不是一个选择。
我正在处理一个非常大而复杂的系统,该系统专门设计用于在循环中同步进行批处理。
我突然使用HttpClient的原因是因为在此之前,用于批处理的所有数据都是从SQL数据库中收集的,而现在我们将Web API调用添加到了混合中。
是的,我们正在同步执行循环中调用Web API。我知道。重写整个事情是异步的不是一个选择。这实际上是我们想要做的。(我们正在尽可能减少API调用的次数)
实际上,我确实尝试在调用链上传播异步行为,但是后来我发现自己有50个文件有很深的变化,仍然有数百个编译器错误需要解决,并失去了所有希望。我被打败了。
因此,回到问题所在,考虑到Microsoft的建议,从不使用WebRequest进行新开发,而改用HttpClient(仅提供异步API),我该怎么办?
这是我在做什么的伪代码...
foreach (var thingToProcess in thingsToProcess)
{
thingToProcess.ProcessStuff(); // This makes an API call
}
Run Code Online (Sandbox Code Playgroud)
如何实现ProcessStuff()?
我的第一个实现看起来像这样
public void ProcessStuff()
{
var apiResponse = myHttpClient // this is an instance of HttpClient
.GetAsync(someUrl)
.Result;
// do some stuff with the apiResponse
}
Run Code Online (Sandbox Code Playgroud)
但是,我被告知,由于同步上下文而从ASP.NET之类的方法调用.Result时,以这种方式调用它可能导致死锁。
猜猜是什么,该批处理过程将从ASP.NET控制器开始。是的,再次,我知道,这很愚蠢。从ASP.NET运行时,它仅是“批处理”一项,而不是整个批处理,但是我离题了,它仍然从ASP.NET调用,因此我担心死锁。
那么解决这个问题的“正确方法”是什么?
我正在使用一个httpclient实例发送多个请求来休息web api以获取数据.这是我的代码的样子:
首先,我有一个控制层,用于调用数据的数据层.
public class ControlLayer
{
protected DataLayer dal;
//constructors here
public int getInfo1(int param)
{
int ret = this.dal.getInfo1(param);
return ret;
}
public int getInfo2(int param)
{
int ret = this.dal.getInfo2(param);
return ret;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有调用webAPI的dataLayer,它看起来像这样.这里为了简单起见,我直接使用.result.
public class DataLayer
{
HttpClient client = new HttpClient();
string url = "";
public int getInfo1(int param1)
{
int ret=0;
HttpResponseMessage response = client.GetAsync(url).Result;
//.... do some work, get the value for ret
return ret;
}
public int getInfo2(int param1)
{
int …Run Code Online (Sandbox Code Playgroud) 在我的场景中,我必须将数据从一个 Web 应用程序发送到一个有效的数据存储 webapi。请求必须是同步的,Exception如果出现问题,我绝对希望抛出,因为这意味着应用程序的关键部分不可用。
这是现有问题的衍生,但不是重复;为什么使用 HttpClient 进行同步连接。
然而一遍又一遍,包括在我上面看到的文章中,我看到一致的建议使用HttpClient,即使在同步场景中也是如此。我看到的最好的原因是上面 SO 帖子中接受的答案,但它基本上归结为;
使用它是因为“闪亮”。
对于我的场景,我不喜欢这是一个可接受的答案。我更愿意为手头的任务使用正确的对象,这似乎是较旧的HttpWebRequest. 甚至 Ben Watson 的优秀资源“编写高性能 .NET 代码”也说明了以下内容;
另一个例子是
System.Net.HttpWebRequest类,如果它收到来自服务器的非 200 响应,它将抛出异常。幸运的是,这种奇怪的行为System.Net.Http.HttpClient在 .NET 4.5的类中得到了纠正
但在我的情况,我其实不希望这样的行为。虽然 有很多很好的用例HttpClient,但谁能提供一个不在HttpWebRequest我的场景中使用的好理由?我是否使用了正确的对象?更重要的是,为什么?
c# ×8
async-await ×6
asynchronous ×4
asp.net ×1
asp.net-mvc ×1
c#-5.0 ×1
httpclient ×1
task ×1