C# 在C中加载图像需要很长时间#

C# 在C中加载图像需要很长时间#,c#,C#,我的问题是: 我试着下载1000多张图片->它可以工作,但是加载下载的图片需要很长时间,程序会继续下载下一张图片等等。。。直到我们承认100,但第8张图片仍然没有完成下载 因此,我想了解我为什么会在这里遇到这样的问题和/或如何解决这个问题 希望看到一个问题 private string DownloadSourceCode(string url) { string sourceCode = ""; try { using (WebCl

我的问题是:

我试着下载1000多张图片->它可以工作,但是加载下载的图片需要很长时间,程序会继续下载下一张图片等等。。。直到我们承认100,但第8张图片仍然没有完成下载

因此,我想了解我为什么会在这里遇到这样的问题和/或如何解决这个问题

希望看到一个问题

private string DownloadSourceCode(string url)
{
    string sourceCode = "";

    try
    {
        using (WebClient WC = new WebClient())
        {
            WC.Encoding = Encoding.UTF8;
            WC.Headers.Add("Accept", "image / webp, */*");
            WC.Headers.Add("Accept-Language", "fr, fr - FR");
            WC.Headers.Add("Cache-Control", "max-age=1");
            WC.Headers.Add("DNT", "1");
            WC.Headers.Add("Origin", url);
            WC.Headers.Add("TE", "Trailers");
            WC.Headers.Add("user-agent", Fichier.LoadUserAgent());

            sourceCode = WC.DownloadString(url);
        }
    }
    catch (WebException e)
    {
        if (e.Status == WebExceptionStatus.ProtocolError)
        {
            string status = string.Format("{0}", ((HttpWebResponse)e.Response).StatusCode);
            LabelID.TextInvoke(string.Format("{0} {1} {2} ", status,
                                                    ((HttpWebResponse)e.Response).StatusDescription,
                                                    ((HttpWebResponse)e.Response).Server));
        }
    }
    catch (NotSupportedException a) 
    { 
        MessageBox.Show(a.Message); 
    }

    return sourceCode;
}

private void DownloadImage(string URL, string filePath)
{
    try
    {
        using (WebClient WC = new WebClient())
        {
            WC.Encoding = Encoding.UTF8;
            WC.Headers.Add("Accept", "image / webp, */*");
            WC.Headers.Add("Accept-Language", "fr, fr - FR");
            WC.Headers.Add("Cache-Control", "max-age=1");
            WC.Headers.Add("DNT", "1");
            WC.Headers.Add("Origin", "https://myprivatesite.fr//" + STARTNBR.ToString());
            WC.Headers.Add("user-agent", Fichier.LoadUserAgent());

            WC.DownloadFile(URL, filePath);

            NBRIMAGESDWLD++;
        }

        STARTNBR = CheckBoxBack.Checked ? --STARTNBR : ++STARTNBR;
    }
    catch (IOException)
    {
        LabelID.TextInvoke("Accès non autorisé au fichier");
    }
    catch (WebException e) 
    {
        if (e.Status == WebExceptionStatus.ProtocolError)
        {
            LabelID.TextInvoke(string.Format("{0} / {1} / {2} ", ((HttpWebResponse)e.Response).StatusCode,
                                                                        ((HttpWebResponse)e.Response).StatusDescription,
                                                                        ((HttpWebResponse)e.Response).Server));
        }
    }
    catch (NotSupportedException a) 
    { 
        MessageBox.Show(a.Message); 
    }
}

private void DownloadImages()
{
    const string URL = "https://myprivatesite.fr/";

    string imageIDURL = string.Concat(URL, STARTNBR);

    string sourceCode = DownloadSourceCode(imageIDURL);

    if (sourceCode != string.Empty)
    {
        string imageNameURL = Fichier.GetURLImage(sourceCode);

        if (imageNameURL != string.Empty)
        {
            string imagePath = PATHIMAGES + STARTNBR + ".png";
            LabelID.TextInvoke(STARTNBR.ToString());
            LabelImageURL.TextInvoke(imageNameURL + "\r");

            DownloadImage(imageNameURL, imagePath);

            Extension.SaveOptions(STARTNBR, CheckBoxBack.Checked);
        }
    }

    STARTNBR = CheckBoxBack.Checked ? --STARTNBR : ++STARTNBR;
}

// END FUNCTIONS

private void BoutonStartPause_Click(object sender, EventArgs e)
{
    if (Fichier.RGBIMAGES != null)
    {
        if (boutonStartPause.Text == "Start")
        {
            boutonStartPause.ForeColor = Color.DarkRed;
            boutonStartPause.Text = "Pause";

            if (myTimer == null)
                myTimer = new System.Threading.Timer(_ => new Task(DownloadImages).Start(), null, 0, Trackbar.Value);
        }
        else if (boutonStartPause.Text == "Pause")           
            EndTimer();

        Extension.SaveOptions(STARTNBR, CheckBoxBack.Checked);
    }
}
因此,我想了解我为什么会在这里遇到这样的问题和/或如何解决这个问题

我想大概有两个原因

  • 连接/端口耗尽
  • 线程池耗尽
连接/端口耗尽 当您试图一次创建太多连接时,或者当您以前创建的连接尚未释放时,就会发生这种情况。当你使用一个软件时,它使用的资源有时不会立即被释放。这会导致在释放该对象和下一个尝试使用相同端口/连接的用户实际访问该端口之间的延迟

最有可能导致连接/端口耗尽的示例

inti=1_000;
而(i-->0)
{
使用var Client=new WebClient();
//做一些网络客户端的事情
}
当您创建大量web客户端时,由于
WebClient
中固有的并发性不足,这有时是必要的。有可能在下一个
WebClient
实例化时,上一个使用的端口可能还不可用,导致延迟(在等待端口时)或更糟的是,下一个
WebClient
打开另一个端口/连接。这可能会导致一个永无止境的连接列表打开,导致事情陷入停顿

疲惫
这是由于试图一次创建过多的
任务
线程
对象(通过或长时间运行的操作)来阻止它们自己的执行而造成的

通常这不是一个问题,因为内置程序在跟踪许多任务方面做得非常好,并确保它们都能轮到执行代码

当这成为一个问题时,
TaskScheduler
没有上下文说明哪些任务是重要的,或者哪些任务需要比其他任务更多的时间来完成。因此,当许多任务正在处理长时间运行的操作、阻塞或抛出异常时,
TaskScheduler
必须等待这些任务完成,然后才能启动新任务。如果您特别不走运,
任务调度器
可以启动一组全部阻塞的任务,没有任务可以启动,即使等待的所有其他任务都很小,并且会立即完成

您通常应该使用尽可能少的任务来提高可靠性并避免线程池耗尽

你能做什么
您有几个选项可以帮助提高此代码的可靠性和性能

  • 考虑改用。我知道您可能需要使用
    WebClient
    ,因此我专门使用
    WebClient
    提供了答案
  • 考虑在同一任务中请求多个下载/字符串,以避免线程池耗尽
  • 考虑使用
    WebClient
    helper类,该类限制可立即激活的可用WebClient,并且如果您要多次访问同一网站,则可以保持WebClient打开
WebClient
Helper类

我创建了一个非常简单的助手类来帮助您入门。这将允许您异步创建
WebClient
请求,而不必担心一次创建太多客户端。默认限制是客户端处理器中的内核数(这是任意选择的)

公共类ConcurrentWebClient
{
//限制一次可以打开的最大客户端数
公共静态int MaxConcurrentDownloads=>Environment.ProcessorCount;
//保存所有应保持打开状态的客户端
私有静态只读ConcurrentDictionary客户端;
//防止同时打开超过分配的WebClient
公共静态只读信号量LIM锁存器;
//允许取消客户端
private static CancellationTokenSource-TokenSource=new();
静态ConcurrentWebClient()
{
Clients=新的ConcurrentDictionary();
Locker???=新信号量LIM(MaxConcurrentDownloads,MaxConcurrentDownloads);
}
//创建新的客户端,或者如果提供了名称,则从字典中检索它,这样我们就不需要创建超出需要的内容
专用异步任务CreateClient(字符串名称、bool持久性、CancellationToken令牌)
{
//在创建新词典之前,请尝试从词典中检索它
if(客户机名称)
{
返回客户[名称];
}
WebClient newClient=new();
if(持久性)
{
//尝试将客户机添加到dict,以便我们以后可以引用它
while(Clients.TryAdd(Name,newClient)为false)
{
token.ThrowIfCancellationRequested();
//在等待添加新客户端时,允许其他任务执行工作
等待任务。延迟(1,令牌);
}
}
返回新客户;
}
//允许发送基本的动态请求,而无需在此类之外创建WebClient
公共异步任务NewRequest(Func表达式,int?MaxTimeout=null,字符串Id=null)
{
//确保一次打开的客户端数不超过最大值
//选择100秒是因为WebClient的默认超时为100秒
wait Locker.WaitAsync(MaxTimeout±10