C# 并行for中的Dispose比常规for循环慢。为什么?

C# 并行for中的Dispose比常规for循环慢。为什么?,c#,multithreading,unmanaged-memory,unmanagedresources,C#,Multithreading,Unmanaged Memory,Unmanagedresources,我已将我的原始问题简化为此测试 使用此类: public class Unmanaged : IDisposable { private IntPtr unmanagedResource; public Unmanaged() { this.unmanagedResource = Marshal.AllocHGlobal(10 * 1024 * 1024); } public void DoSomethingWithThisClass()

我已将我的原始问题简化为此测试

使用此类:

public class Unmanaged : IDisposable
{
    private IntPtr unmanagedResource;

    public Unmanaged()
    {
        this.unmanagedResource = Marshal.AllocHGlobal(10 * 1024 * 1024);
    }
    public void DoSomethingWithThisClass()
    {
        Console.WriteLine($"{DateTime.Now} - {this.unmanagedResource.ToInt64()}");
    }

    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            Marshal.FreeHGlobal(unmanagedResource);
            disposedValue = true;
        }
    }

    ~Unmanaged() {
       Dispose(false);
     }

    void IDisposable.Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
我有两个测试:

public class UnitTest1
{
    const int Runs = 100000;

    [TestMethod]
    public void UsingFor()
    {
        for (var i = 0; i <= Runs; i++)
        {
            using (var unman = new Unmanaged())
            {
                unman.DoSomethingWithThisClass();
            }
        }
    }

    [TestMethod]
    public void UsingParallelFor()
    {
        Parallel.For(0, Runs, new ParallelOptions() { MaxDegreeOfParallelism = 10},
            index => {
                using (var unman = new Unmanaged())
                {
                    unman.DoSomethingWithThisClass();
                }
            });
    }
}
公共类UnitTest1
{
const int Runs=100000;
[测试方法]
用于()的公共作废
{
对于(var i=0;i{
使用(var unman=new Unmanaged())
{
使用this class()取消man.doSomethingWith类;
}
});
}
}
ParallelFor通常需要两倍于常规for的时间。根据分析器,62%-65%的执行时间花费在ParallelFor的FreeHGlobal中。只有52%-53%是在FreeHGlobal内部进行的常规消费

我认为对于现代RAM系统来说,这不会有太大的区别。有没有办法在多个进程中处理大块的非托管内存?有没有一种方法可以将其更改为多线程

如果我不处理每个进程中使用的RAM(不好的主意,但只是为了测试),Parallel For的速度是前者的两倍,但在应用程序崩溃之前,我只能在同一时间打开其中的4-5个(它们是大量图像数据)(正如你所猜测的,内存不足例外)

为什么在不同对象上执行多个Dispose操作会减慢速度

如果这是唯一的选择,我可以让它们保持单线程,但我希望加快速度


谢谢。

免费全球几乎可以肯定。这意味着您的进程中一次只能有一个线程运行它。他们排队等候。这是有开销的,所以速度较慢


您可以通过创建一个大的非托管内存块并在其中运行无锁分配器来加快速度。

FreeHGlobal几乎肯定是块。这意味着您的进程中一次只能有一个线程运行它。他们排队等候。这是有开销的,所以速度较慢


您可以通过创建一大块非托管内存并在其中运行无锁分配器来加快速度。

AllocHGlobal()中内置了一个锁,它保证了堆线程的安全。因此,您要衡量的是锁被持有的时间,当另一个线程也在忙于分配内存时,它不可避免地需要更长的时间。AllocHGlobal()中内置了一个锁,它保证了堆线程的安全。因此,您要测量的是锁被持有的时间,当另一个线程也在忙于分配内存时,它不可避免地需要更长的时间。我没有意识到有一个内部锁。这使我不得不以不同的方式处理这个问题。我喜欢你的想法,创建一个足够大的内存块,一次将其中四个内存块放入RAM。然后,我可以在队列中设置需要处理的作业,并让控制器将这些进程划分为RAM工作区的不同块。在从队列中开始另一个任务之前,我可以清除前一个流程中使用的部分。这是一个多一点的编码开销,但应该节省几个小时的处理量,需要做这些。你肯定是按照正确的路径在那里我的经验。试着想想你不需要锁定就可以做到这一点的方法,或者,看看外面美妙的内存池。我没有意识到有一个内部锁。这使我不得不以不同的方式处理这个问题。我喜欢你的想法,创建一个足够大的内存块,一次将其中四个内存块放入RAM。然后,我可以在队列中设置需要处理的作业,并让控制器将这些进程划分为RAM工作区的不同块。在从队列中开始另一个任务之前,我可以清除前一个流程中使用的部分。这是一个多一点的编码开销,但应该节省几个小时的处理量,需要做这些。你肯定是按照正确的路径在那里我的经验。试着想一想你不需要锁定就可以做到这一点的方法,或者,看看外面美妙的内存池。