【问题标题】:Load an image from web with new thread使用新线程从 Web 加载图像
【发布时间】:2014-02-24 00:19:06
【问题描述】:

我正在尝试将图像从网络服务器加载到图片框。为了在加载图片之前不阻塞表单,我启动了一个新线程,该线程在 LoadPicture() 函数上工作,直到所有工作完成。

一切都将在 MouseHover-Event 上启动,因此它可以在短时间内多次触发,因为默认的 WindowsHoverTime 是 180 毫秒并且无法更改(我对此进行了很多搜索)。 这是函数:

public void LoadPicture(string url)
{
    try
    {
        WebRequest req = HttpWebRequest.Create(url);
        req.Timeout = 3500;
        req.Method = "HEAD";
        using (WebResponse resp = req.GetResponse())
        {
            int ContentLength;
            if (int.TryParse(resp.Headers.Get("Content-Length"), out ContentLength))
            {
                string ContentType = resp.Headers.Get("Content-Type");
                if (ContentLength < 1048576 && ContentType == "image/png")
                {
                    this.pictureBox1.Load(url);
                }
                else
                {
                    this.pictureBox1.Image = mainprogram.Properties.Resources.sample;
                }
            }
        }
    }
    catch { this.pictureBox1.Image = mainprogram.Properties.Resources.sample; }
}

如果 url 包含小于 1MB 的 png 文件,则应将其加载到 pictureBox1,如果没有,则从资源中加载默认图像。

线程和调用:

namespace mainprogram
{
    public partial class Form1 : Form
    {
        Thread threadworker;
        .
        .
        .
        private void button1_MouseHover(object sender, EventArgs e)
        {
            if (threadworker.IsAlive == false)
            {
                threadworker = new Thread(() => LoadPicture(url));
                threadworker.Start();
            }
        }

现在的问题是:线程几乎总是会失败。 Catch{} 将执行 9/10 次。主要在 WebResponse resp = req.GetResponse() 崩溃。如果我在同一个线程中使用该函数(不启动一个新线程),它会正常加载,但 GUI 将停止响应 3 秒,直到图片加载完毕。

编辑:有时它确实有效,所以我不确定我做错了什么。

【问题讨论】:

  • 你得到了什么异常?
  • 你应该使用异步 HttpClient 而不是线程。
  • 什么都没有,因为我使用 try&catch,它只会失败并触发 catch{} 短语
  • @SLaks 你能举个简单的例子吗?

标签: c# multithreading visual-studio-2013 webrequest system.net


【解决方案1】:

使用async

为了举例说明 SLaks 的出色评论,这里是 MSDN 上如何使用 async/await for web http://msdn.microsoft.com/en-us/library/hh300224.aspx#BKMK_ConvertGtBtArr

的演练

this answer to a similar question 上还有很多关于 async/await 的工作原理和好处的解释。

使用 .NET 4.0

还有一个异步版本的GetResponse 可用于.NET 4.0(及更低版本),称为BeginGetResponse。它记录在 MSDN http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(v=vs.100).aspx 上,但该页面上的示例很糟糕,因为它阻止了使用事件。相反,您想要的是在 UI 线程中调用您的回调。 async/await 自动执行此操作。对于回调,您可能必须手动将回调推迟到 UI syncContext。

备注

无论如何,所有这些都只有在您的实际问题是访问冲突时才有用,因为您尝试在非 UI 线程中绘制请求的图像和/或阻塞 UI。相反,如果 GetResponse 因 DNS 问题、错误 403/404、超时或类似原因引发异常,您应该投入精力找出原因。

【讨论】:

  • 不幸的是,HttpClient 仅在 .NET 4.5 中可用。我精简了我的应用程序以使用 4.0,因为相当多的用户不想安装新的 .NET Framework。有没有不需要4.5的解决方案?
【解决方案2】:

好的,经过大量的研究和麻烦,我得到了它的工作。 首先,我要感谢 SLaks 的评论。我使用了 async/await + GetResponseAsync 并且它运行良好:

public async void LoadPicture(string url)
{
    bool worker = await GetURLContentsAsync(url);
}

private async Task<bool> GetURLContentsAsync(string url)
{
    var webReq = (HttpWebRequest)WebRequest.Create(url);             
    using (WebResponse response = await webReq.GetResponseAsync())
    {
        .
        .
        .

不幸的是,GetResponseAsync 仅在 .NET Framework 4.5 中可用,所以我从这里尝试了一种不同的 BeginGetResponse 方法: https://www.informit.com/guides/content.aspx?g=dotnet&seqNum=583 但它要么阻塞了 UI 线程(非异步),要么无法加载图片 3/4 次(相同的图像)。

所以我最终再次使用线程:

private void LoadPicture(string url)
{
    threadworker = new Thread(() => pictureBox1.Image = getImgFromUrl(url));
    threadworker.Start();
} 

public Bitmap getImgFromUrl(string url)
{
    Bitmap bmp = null;
    try
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        try
        {
            bmp = new Bitmap(response.GetResponseStream());
            .
            .
            .

正如您所看到的,它与问题帖子中的代码几乎相同,我发现 threadworker.IsAlive 是罪魁祸首,而 pictureBox1.Load() 比将流写入临时位图文件花费的时间要长得多然后加载它。

【讨论】:

    猜你喜欢
    • 2011-02-26
    • 2011-11-22
    • 2023-04-11
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 2012-07-30
    相关资源
    最近更新 更多