代码之家  ›  专栏  ›  技术社区  ›  gafs

为什么延迟任务不能完全执行或阻塞用户界面?

  •  2
  • gafs  · 技术社区  · 8 年前
    private async Task<string> httpClient(CancellationToken cancelToken)
    {
        HttpClient hc = new HttpClient();
    
        hc.Timeout = new TimeSpan(0, 0, 10);
    
        //Task.Delay(5000).Wait(); using this one, it blocks the UI thread
        //await Task.Delay(5000); using this one, it doesn't execute the task after delay
    
        if (cancelToken.IsCancellationRequested)
        {
            return null;
        }
    
        HttpResponseMessage response = await hc.GetAsync(new Uri("http://google.com/"));
    
        response.EnsureSuccessStatusCode();
    
        string responseData = await response.Content.ReadAsStringAsync();
    
        return responseData;
    }
    

    这是我的异步任务,我在尝试在其中使用延迟时遇到了一个问题。我尝试了两种方法,两种方法似乎都会导致任务出现问题。尝试研究,但找不到解决问题的方法。感谢您的帮助

    代码的其他部分:

    private async void Test()
    {
        string response = await httpClient(token);
        Console.WriteLine("response: " + response);
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        Task t = new Task(Test);
        t.Start();
        Console.WriteLine("task started");
        t.Wait();
        Console.WriteLine("task finished");
    }
    
    1 回复  |  直到 8 年前
        1
  •  3
  •   Marc Gravell    8 年前

    问题在于:

    private async void Test()
    {
        string response = await httpClient(token);
        Console.WriteLine("response: " + response);
    }
    

    只要你做了什么 async void 您已完全删除任何跟踪状态的功能。你的 new Task(Test); 正在使用 new Task(Action) ,它将在代码第一次返回调用方时(即在第一次未完成时)报告完成 await (在您的案例中:the Task.Delay ). 要想做你想做的事,你真的应该使用 Task.Run(Func<Task>) API(或避免 Task.Run / Task.Start 完全依赖于异步管道本身),具有 private async Task Test() 方法

    然后,您的事件处理程序可以是:

    private async void button1_Click(object sender, EventArgs e)
    {
        Console.WriteLine("about to start task");
        var t = Task.Run(Test);
        Console.WriteLine("task started");
        await t;
        Console.WriteLine("task finished");
    }
    

    或者为了避免额外的线程(如Nkosi所述):

    private async void button1_Click(object sender, EventArgs e)
    {
        Console.WriteLine("about to start task");
        var t = Test();
        Console.WriteLine("task started");
        await t;
        Console.WriteLine("task finished");
    }