如何运行运行任务计划

时间:2018-12-14 16:24:12

标签: c# task-parallel-library

我有代码:

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秒钟后开始。那我该怎么办呢?谢谢

3 个答案:

答案 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;

            }
        }

这里需要注意的几件事-

  1. 如果发送HTTP调用需要 超过4秒,您的代码将被延迟 发送邮件所花费的时间,即使超过4秒也是如此。
  2. 通过 不等待HTTP调用完成,则无法使用 结果HTML

您可以通过续篇来解决此问题-

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; }
}