我有代码:
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
var html = await client.GetStringAsync(url);
Console.WriteLine($"retrieved {html.Length} characters from {url}");
}
}
所有任务client.GetStringAsync(url)将同时执行。但是我想在超时后为每个URL调用client.GetStringAsync(无需等待上一个任务完成)。例如:
at 00:00:01 - GetStringAsync url1
at 00:00:05 - GetStringAsync url2
at 00:00:09 - GetStringAsync url3
每个任务将在4秒钟后开始。那我该怎么办呢?谢谢
答案 0 :(得分:1)
如果您不想等待查询URL,请不要等待。如果要在4秒钟(或任何其他固定时间段)后运行延续,请使用Task.Delay
。
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
ProcessURL(url);
await Task.Delay(TimeSpan.FromSeconds(4));
}
async Task ProcessURL(string url)
{
try
{
var html = await client.GetStringAsync(url);
Console.WriteLine($"retrieved {html.Length} characters from {url}");
}
catch (Exception e)
{
//TODO handle any errors in processing the URL
}
}
}
请注意,由于ProcessURL
没有任何等待,因此它将需要负责处理内部可能发生的任何错误,因为没有调用者能够处理它们。
答案 1 :(得分:0)
您是说要在两次技术呼叫之间等待4秒,而不是等待上一个呼叫完成吗?
您可以为此使用Task.Delay
-
public static async Task Download()
{
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"http://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
var client = new HttpClient();
foreach (var url in urls)
{
var waitingTask = Task.Delay(1000 * 4); //4000 milliseconds
var fireAndForget = client.GetStringAsync(url);
await waitingTask;
}
}
这里需要注意的几件事-
您可以通过续篇来解决此问题-
client.GetStringAsync(url).ContinueWith(task => Console.WriteLine($"retrieved {task.Result.Length} characters from {url}"));
编辑-根据@Servy的评论添加完整性-
我上面的继续示例非常不完整,旨在传达处理未完成任务结果的想法。在使用结果和处理错误方面,都有多种处理下载过程的方法。这是一种使用ContinueWith
的方法,但是会检查下载是如何完成而不是假设下载成功-
var task = client.GetStringAsync(url);
task.ContinueWith(task =>
{
// task completed correctly, do something with the result, like -
Console.WriteLine($"retrieved {task.Result.Length} characters from {url}");
}, TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(task =>
{
// task did not complete successfully, you can check why using the task iteslf, for example
if (task.IsFaulted)
{
// the task failed with an unhandled exception, you can access the exception instance if you want, for example -
Console.WriteLine($"Error while downloading from {url} - {task.Exception}");
}
}, TaskContinuationOptions.NotOnRanToCompletion);
答案 2 :(得分:-1)
使用Task.Delay Check 并在每次通话之间等待4秒
HttpClientHelper:HTTP请求包装器
HttpResult:包装请求结果
public static async Task Download()
{
HttpClientHelper clientHelper = new HttpClientHelper();
List<HttpResult> httpResults = new List<HttpResult>();
var urls = new[] {
"https://github.com/naudio/NAudio",
"https://twitter.com/mark_heath",
"https://github.com/markheath/azure-functions-links",
"https://pluralsight.com/authors/mark-heath",
"https://github.com/markheath/advent-of-code-js",
"https://stackoverflow.com/users/7532/mark-heath",
"https://mvp.microsoft.com/en-us/mvp/Mark%20%20Heath-5002551",
"https://github.com/markheath/func-todo-backend",
"https://github.com/markheath/typescript-tetris",};
foreach (var url in urls)
{
HttpResult httpResult = clientHelper.GetStringAsync(url);
httpResults.Add(httpResult);
if (httpResult.HasError)
{
Console.WriteLine($"Error occurred: '{httpResult.Error}' on characters from {url}");
}
else
{
Console.WriteLine($"retrieved {httpResult.Result.Length} characters from {url}");
}
await Task.Delay(5000);
}
}
public class HttpClientHelper
{
public async Task<HttpResult> GetStringAsync(string url)
{
HttpResult httpResult = new HttpResult
{
URL = url
};
try
{
HttpClient client = new HttpClient();
httpResult.Result = await client.GetStringAsync(url);
}
catch (Exception e)
{
//todo:handel Exception
httpResult.HasError = true;
httpResult.Error = e.Message + Environment.NewLine + e.InnerException?.Message;
}
return httpResult;
}
}
public class HttpResult
{
public string URL { get; set; }
public bool HasError { get; set; }
public string Error { get; set; }
public string Result { get; set; }
}