C# 在C中加载图像需要很长时间#
我的问题是: 我试着下载1000多张图片->它可以工作,但是加载下载的图片需要很长时间,程序会继续下载下一张图片等等。。。直到我们承认100,但第8张图片仍然没有完成下载 因此,我想了解我为什么会在这里遇到这样的问题和/或如何解决这个问题 希望看到一个问题C# 在C中加载图像需要很长时间#,c#,C#,我的问题是: 我试着下载1000多张图片->它可以工作,但是加载下载的图片需要很长时间,程序会继续下载下一张图片等等。。。直到我们承认100,但第8张图片仍然没有完成下载 因此,我想了解我为什么会在这里遇到这样的问题和/或如何解决这个问题 希望看到一个问题 private string DownloadSourceCode(string url) { string sourceCode = ""; try { using (WebCl
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
- 考虑在同一任务中请求多个下载/字符串,以避免线程池耗尽
- 考虑使用
helper类,该类限制可立即激活的可用WebClient,并且如果您要多次访问同一网站,则可以保持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