2017-02-09 44 views
2

我已將原始問題簡化爲此測試。並行內部的處理比循環的常規要慢。爲什麼?

使用這個類:

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通常需要大約只要定期兩次。根據Profiler的說法,62%-65%的執行時間花在FreeHGlobal的ParallelFor中。 FreeHGlobal僅花費了52%-53%的費用。

我認爲與現代RAM系統,這不會有太大的區別。有沒有辦法在多個進程中處理大量未受管理的內存?有沒有一種方法可以改變它使其具有多線程?

如果我不處理每個進程中使用的RAM(糟糕的想法,但只是爲了測試),Parallel For是兩倍的速度,但然後我只能打開大約4-5個(它們是大量的的圖像數據)在應用程序崩潰之前(根據您的猜測,出現內存異常)。

爲什麼在單獨對象上執行多個Dispose動作會減慢速度?

我可以讓他們單線程,如果這是唯一的選擇,但我希望加快這一點。

謝謝。

+0

如果您將'Unmanaged'作爲'sealed'類,那麼編寫'Dispose()'更容易,因爲不需要'virtual Dispose(bool)'。 –

+1

AllocHGlobal()中內置了一個鎖,它使堆保持線程安全。所以你測量的是鎖持續了多長時間,不可避免地需要更長的時間,而另一個線程也忙於分配內存。 –

+0

如果你正在處理大量的非託管資源('10 * 1024 * 1024'可能是代理),你可能會考慮C++/CLI而不是P/Invoke; C++也可以給你更多的工具來管理內存。 –

回答

0

FreeHGlobal幾乎肯定會阻止。這意味着您的進程中只有一個線程可以一次運行它。他們排隊等待。這有些開銷,所以速度較慢。

通過創建一個非託管內存的大塊並在其中運行無鎖分配器,可以使其更快。

+1

我沒有意識到有內部鎖。這使我不得不以不同的方式處理這個問題。 我喜歡你的想法,即創建一個足夠大的內存塊,以將其中的四個一次放入RAM中。然後,我可以設置需要在隊列中處理的作業,並讓控制器將進程分成不同的RAM工作區塊。在從隊列中開始另一個任務之前,我可以清除以前進程中使用的一個部分。這是一個更多的編碼開銷,但應該節省數小時的處理量,這些都需要完成。 –

+0

在我的經歷中,你絕對遵循正確的道路。試着想想你可以不用鎖定就可以做到的方式,或者考慮一下那些美妙的記憶池。 – hoodaticus

相關問題