Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#Parallel.ForEach()内存使用量不断增长_C#_Multithreading_.net Core - Fatal编程技术网

C#Parallel.ForEach()内存使用量不断增长

C#Parallel.ForEach()内存使用量不断增长,c#,multithreading,.net-core,C#,Multithreading,.net Core,在连续运行9小时后,我仍然观察到内存使用量在增加,尽管内存使用量增长缓慢 只是想知道,是不是因为我没有释放内存使用的跟踪文件 顺便说一句,我使用更新文件元数据,不幸的是,它没有实现IDisposable接口。使用WebClient.DownloadFile()直接下载到一个文件,这样您就不会将整个文件都存储在内存中。该方法用于并行化CPU绑定的工作负载。下载文件是I/O绑定的工作负载,因此并行.ForEach不适合这种情况,因为它不必要地阻止线程池线程。正确的方法是异步执行,使用async/aw

在连续运行9小时后,我仍然观察到内存使用量在增加,尽管内存使用量增长缓慢

只是想知道,是不是因为我没有释放内存使用的跟踪文件


顺便说一句,我使用更新文件元数据,不幸的是,它没有实现IDisposable接口。

使用
WebClient.DownloadFile()
直接下载到一个文件,这样您就不会将整个文件都存储在内存中。

该方法用于并行化CPU绑定的工作负载。下载文件是I/O绑定的工作负载,因此并行.ForEach不适合这种情况,因为它不必要地阻止
线程池
线程。正确的方法是异步执行,使用async/await。提出异步web请求的推荐类是,而控制并发级别的最佳选项是库。对于这种情况,使用这个库中最简单的组件就足够了,类:

异步任务下载列表异步(列表) { 使用(var httpClient=new httpClient()) { var rest=ExcludeDownloaded(列表); var block=新操作块(异步链接=> { 等待下载FileAsync(httpClient,链接); },新的ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism=10 }); foreach(rest中的var链接) { wait block.SendAsync(链接); } block.Complete(); 等待区块完成; } } 异步任务下载文件异步(HttpClient HttpClient,字符串链接) { var fileName=Guid.NewGuid().ToString();//生成唯一文件名的代码; var filePath=Path.Combine(保存路径,文件名); 如果(File.Exists(filePath))返回; var response=wait httpClient.GetAsync(link); response.EnsureSuccessStatusCode(); 使用(var contentStream=await response.Content.ReadAsStreamAsync()) 使用(var fileStream=newfilestream)(filePath,FileMode.Create, FileAccess.Write,FileShare.None,32768,FileOptions.Asynchronous) { 等待contentStream.CopyToAsync(文件流); } } 使用
HttpClient
下载文件的代码并不像
WebClient.DownloadFile()
那么简单,但为了保持整个过程的异步(从web读取和写入磁盘),您必须这样做



警告:异步文件系统操作当前在.NET中。为了获得最大效率,最好避免在
FileStream
构造函数中使用
FileOptions.Asynchronous
选项。

这不一定是内存泄漏,可能是垃圾收集器没有运行。
File.writealBytes(文件名,数据)您有多大的
数据
?你试过按块写吗?因为你并行处理这些项目,你在内存中保存了每个下载文件的内容——同时保存了多个。这就是为什么它会增加的原因,特别是当它们是大文件时。正如@Sean所提到的,GC很可能还没有清理。hi@PavelAnikhouski大多数时候,文件将小于1MB,但也可能超过100MB,目前最大的是155MB。如何按块编写?@riQQ DownloadFile()解决了这个问题。谢谢出于好奇,如果我使用File.writealBytes(),每次使用后如何释放它的内存?@Franva基本上,你是在分配大字节数组。它们是由.NET专门处理的。您可以在此处阅读更多内容:
GC.Collect()
如果不再持有对对象/字节数组的任何引用,则释放内存。@riQQ确实如此。但是请看一看:重要-我们不建议您在新开发中使用WebClient类。相反,请使用System.Net.Http.HttpClient类。@riQQ
HttpClient
应该提供更好的性能,因为它重用连接。这是因为您不必为每个请求创建一个新实例,就像您必须使用
WebClient
一样。这是一个漂亮的解决方案,有丰富的解释、答案和注释~!很好的例子~!谢谢我会在午休时间尝试一下(我已经开始工作了)>\u@Franva如果你想做一个公平的比较,你应该在
Parallel.ForEach
方法之前加上这一行:
ThreadPool.SetMinThreads(50,10);
,因此
线程池
有50个线程可用于执行50个并发web请求。如果没有这一行,您将引入由饥饿的
线程池
导致的隐式限制。测试结果表明,远程服务器或web连接无法处理50个并发操作Action,或存储硬件。我建议您尝试使用较小的并发级别。50似乎远远不是最佳值。谢谢@TheodorZoulias,我将尝试并更新它。感谢您的帮助和解释。我已经了解了多线程编程的见解。
public string SavePath { get; set; } = @"I:\files\";

public void DownloadList(List<string> list)
{
    var rest = ExcludeDownloaded(list);
    var result = Parallel.ForEach(rest, link=>
    {
        Download(link);
    });
}

private void Download(string link)
{
    using(var net = new System.Net.WebClient())
    {
        var data = net.DownloadData(link);

        var fileName = code to generate unique fileName;
        if (File.Exists(fileName))
            return;

        File.WriteAllBytes(fileName, data);
    }
}

var downloader = new DownloaderService();
var links = downloader.GetLinks();
downloader.DownloadList(links);
private void Download(string link)
{
    using(var net = new System.Net.WebClient())
    {
        var fileName = code to generate unique fileName;
        if (File.Exists(fileName))
            return;
        var data = net.DownloadFile(link, fileName);
        Track theTrack = new Track(fileName);
        theTrack.Title = GetCDName();
        theTrack.Save();
    }
}
async Task DownloadListAsync(List<string> list)
{
    using (var httpClient = new HttpClient())
    {
        var rest = ExcludeDownloaded(list);
        var block = new ActionBlock<string>(async link =>
        {
            await DownloadFileAsync(httpClient, link);
        }, new ExecutionDataflowBlockOptions()
        {
            MaxDegreeOfParallelism = 10
        });
        foreach (var link in rest)
        {
            await block.SendAsync(link);
        }
        block.Complete();
        await block.Completion;
    }
}

async Task DownloadFileAsync(HttpClient httpClient, string link)
{
    var fileName = Guid.NewGuid().ToString(); // code to generate unique fileName;
    var filePath = Path.Combine(SavePath, fileName);
    if (File.Exists(filePath)) return;
    var response = await httpClient.GetAsync(link);
    response.EnsureSuccessStatusCode();
    using (var contentStream = await response.Content.ReadAsStreamAsync())
    using (var fileStream = new FileStream(filePath, FileMode.Create,
        FileAccess.Write, FileShare.None, 32768, FileOptions.Asynchronous))
    {
        await contentStream.CopyToAsync(fileStream);
    }
}