Parallel for 中的 Dispose 比常规 for 循环慢。为什么?
Dispose inside a Parallel for is slower than a regular for loop. Why?
我已将我的原始问题简化为此测试。
使用这个 class:
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();
}
});
}
}
ParallelFor 通常需要大约两倍于常规 for 的时间。根据探查器,ParallelFor 的 62%-65% 的执行时间花在了 FreeHGlobal 内部。只有 52%-53% 用于常规 for.
我认为对于现代 RAM 系统,这不会产生太大的影响。有没有办法在多个进程中处理大块非托管内存?有什么方法可以改变它使其成为多线程的吗?
如果我不处理每个进程使用的 RAM(坏主意,但只是为了测试),Parallel For 的速度是原来的两倍,但我只能打开其中的大约 4-5 个(它们很大)大量的图像数据)在应用程序崩溃之前同时发生(正如您所猜测的那样,内存不足异常)。
为什么对不同对象执行多个 Dispose 操作会减慢速度?
如果那是唯一的选择,我可以让它们保持单线程,但我希望加快速度。
谢谢。
FreeHGlobal 几乎肯定会阻塞。这意味着您的进程中只有一个线程一次可以 运行 它。他们排队等候。这有开销,所以速度较慢。
您可以通过创建一个大的非托管内存块并在其中 运行设置一个 lock-free 分配器来使其更快。
我已将我的原始问题简化为此测试。
使用这个 class:
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();
}
});
}
}
ParallelFor 通常需要大约两倍于常规 for 的时间。根据探查器,ParallelFor 的 62%-65% 的执行时间花在了 FreeHGlobal 内部。只有 52%-53% 用于常规 for.
我认为对于现代 RAM 系统,这不会产生太大的影响。有没有办法在多个进程中处理大块非托管内存?有什么方法可以改变它使其成为多线程的吗?
如果我不处理每个进程使用的 RAM(坏主意,但只是为了测试),Parallel For 的速度是原来的两倍,但我只能打开其中的大约 4-5 个(它们很大)大量的图像数据)在应用程序崩溃之前同时发生(正如您所猜测的那样,内存不足异常)。
为什么对不同对象执行多个 Dispose 操作会减慢速度?
如果那是唯一的选择,我可以让它们保持单线程,但我希望加快速度。
谢谢。
FreeHGlobal 几乎肯定会阻塞。这意味着您的进程中只有一个线程一次可以 运行 它。他们排队等候。这有开销,所以速度较慢。
您可以通过创建一个大的非托管内存块并在其中 运行设置一个 lock-free 分配器来使其更快。