Я упростил свою первоначальную проблему в этом тесте.Утилизация внутри Parallel for медленнее, чем обычный цикл. Зачем?
Используя этот класс:
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 обычно занимает примерно в два раза до тех пор, как регулярная для. Согласно профилировщику, 62% -65% времени выполнения тратится в FreeHGlobal для ParallelFor. Только 52% -53% расходуется внутри FreeHGlobal для регулярного использования.
Я предполагал, что с современными системами оперативной памяти это не будет иметь особого значения. Есть ли способ обрабатывать большие куски не управляемой памяти в нескольких процессах? Есть ли способ изменить это, чтобы он был многопоточным?
Если я не утилизирую ОЗУ, используемую в каждом процессе (плохая идея, но только для проверки), Parallel For в два раза быстрее, но тогда я могу открыть только 4-5 из них (они большие суммы данных изображения) одновременно до того, как приложение выйдет из строя (с учетом, как вы догадались, исключения из ОЗУ).
Почему несколько объектов Dispose на отдельных объектах замедляют работу?
Я могу оставить их однопоточными, если это единственный вариант, но я надеялся ускорить это.
спасибо.
Если вы сделаете 'неуправляемый'' закрытым' класс, написание 'Dispose()' проще, так как нет необходимости в 'virtual Dispose (bool)'. –
В AllocHGlobal() встроен замок, он сохраняет защиту от кучи. Так что вы измеряете, сколько времени удерживается замок, это неизбежно занимает больше времени, в то время как другой поток также занят распределением памяти. –
Если вы имеете дело с множеством неуправляемых ресурсов ('10 * 1024 * 1024' может быть прокси для этого), вы можете рассмотреть C++/CLI, а не P/Invoke; C++ также может предоставить вам еще несколько инструментов для управления памятью. –