【发布时间】:2019-03-16 20:18:42
【问题描述】:
我正在开发一个 asp.net mvc-5 Web 应用程序,并且我有以下调用来对第 3 方应用程序进行连续的 WebClient() 调用:
public async Task<List<Technology>> GetResource(int? filtertype)
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources?AUTHTOKEN=" + token;
var json = await wc.DownloadStringTaskAsync(url);
resourcesinfo = JsonConvert.DeserializeObject<ResourcesInfo>(json);
}
//for each resource get its tag + add the tag to the list
foreach (var c in resourcesinfo.operation.Details)
{
ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources/" + c.RESOURCEID + "?AUTHTOKEN=" + token;
string tempurl = url.Trim();
var json = await wc.DownloadStringTaskAsync(tempurl);
resourceAccountListInfo = JsonConvert.DeserializeObject<ResourceAccountListInfo>(json);
AllTags.Add(resourceAccountListInfo.SingleOrDefault().CUSTOMFIELDVALUE.ToLower());
}
}
}
目前第一个WebClient 将返回大约1,500 条记录,所以我在foreach 中的第二个WebClient 调用将执行1,500 次,因此整个过程大约需要20 分钟才能完成。那么我该如何改进这个过程呢?
【问题讨论】:
-
是否需要等到1500个请求全部完成后才响应用户?
-
在这种情况下,我想知道是否有办法对它们进行批处理。目前主要是大声思考,所以我没有代码可以回答。但不是在循环的每次迭代中调用
await,而是一次循环5条记录(可配置),构建wc.DownloadStringTaskAsync(tempurl)结果的List<Task<T>>,然后在该列表上执行WaitAll.因此,您一次将有 5 个并行 HTTP 请求,而不是 1 个。根据需要调整 5 的值。 -
可能有一种更简洁的方法,但我的第一个方法是为每个
Task<T>分配一个.ContinueWith(),因为它被添加到列表中。在该函数中,您可以对响应做任何您需要做的事情(似乎将其添加到AllTags)。因此,当WaitAll()完成时,该批次应该被添加到AllTags并且是时候开始下一个批次了。您需要确保在.ContinueWith()和WaitAll()中也有一些仔细的错误处理。在未等待的任务中,错误很容易被忽视。 -
向服务 1 发出 1500 多个请求是非常站不住脚的。在这里没有什么能真正帮助你;这是不可行的。大多数设计良好的 API 将提供某种方式来批处理请求(因为它们不希望您点击 1500 次以上),或者它们会提供某种机制来将相关项目包含在初始请求中。很多支持分页,这样可以进一步减少每个请求的负载。如果您控制 API,则需要实现这些功能,否则您需要更好地阅读文档或向 API 所有者投诉。
-
如果您真的没有其他选择,那么您只需要围绕它编写代码。也许只需列出初始请求的结果,并通过链接或按钮查询每个选择加入的项目的详细信息。至少这样,用户可以快速地获得他们目前需要的东西。
标签: c# asp.net parallel-processing task-parallel-library