winforms 无限下载C#

uwopmtnx  于 2022-11-16  发布在  C#
关注(0)|答案(2)|浏览(172)

我在C#代码中下载文件时遇到问题。

public Form1()
{
    InitializeComponent();

    DownloadFile().Wait();
}
private async Task DownloadFile()
{
    Debug.WriteLine("Download");// appears
    HttpClient client = new();
    var response = await client.GetAsync("file");
    Debug.WriteLine("End download");// does not display
}

下载后线程停止,但应用程序未显示。
线程0x7d28被代码0(0x0)阻止。
线程0x7998被代码0(0x0)中断。
线程0x269c被代码0(0x0)阻止。
线程0x7e74被代码0(0x0)阻止。
线程0x534c被代码0(0x0)阻止。
线程0x77f0被代码0(0x0)阻止。
线程0x70fc被代码0(0x0)中断。
线程0x7428被代码0(0x0)中断。
线程0x5628被代码0(0x0)中断。
线程0x788c被代码0(0x0)中断。
线程0x63f4被代码0(0x0)阻止。

sxissh06

sxissh061#

Classic HttpClient bug。在主线程上等待时导致死锁。用于解决此类问题的ConfigureAwait(false)不适用于HttpClient ...
为了避免这个问题,你需要在另一个线程上强制http调用。为此,你可以将http调用封装在一个任务中,如下所示:

private async Task DownloadFile()
{
    Debug.WriteLine("Download");
    HttpClient client = new();
    var response =  await Task.Run(() =>await client.GetAsync("file"));
    Debug.WriteLine("End download");
}

从.NET 5开始,HttpClient具有(最终)同步方法:

private void DownloadFile()
{
    Debug.WriteLine("Download");
    HttpClient client = new();
    var response = client.Get("file");
    Debug.WriteLine("End download");
}

但是在构造函数或者UI程序的主线程上做繁重的工作是不好的做法,也许你可以考虑使用Form.Load事件。

5gfr0r5j

5gfr0r5j2#

不要将async / await与Wait()或Result结合使用,因为这会导致死锁。
若要避免SynchronizationContext中出现死锁,应使用ConfigureAwait(false):

private async Task DownloadFile()
{
    Debug.WriteLine("Download");// appears
    HttpClient client = new();
    var response = await client.GetAsync("file").ConfigureAwait(false);
    Debug.WriteLine("End download");// does not display
}

相关问题