2010-04-10 28 views
2

我已經被賦予了重新編寫用C#編寫的一些庫的任務,以便在啓動完成後沒有分配。沒有分配的.NET DB查詢?

我剛剛找到一個項目,每30秒對OdbcConnection執行一次數據庫查詢。我總是使用.ExecuteReader()創建一個OdbcDataReader。是否有任何模式(如SocketAsyncEventArgs套接字模式)可讓您重新使用您自己的OdbcDataReader?或者其他一些聰明的方式來避免分配?

因爲所有的dbs在工作都是基於Oracle的,而且最後我檢查過了,所以沒有官方的Linq To Oracle提供者,所以我沒有去學習LINQ。但是如果Linq有辦法做到這一點,我可以使用其中一個第三方。

更新:

我不認爲我明確規定了無ALLOC要求的原因。我們有一個關鍵線程正在運行,非常重要的是它不會凍結。這是一個近乎實時的交易應用程序,我們確實發現一些Gen 2收藏的凍結時間高達100 ms。 (我也聽說用C#編寫相同的遊戲)。有一個後臺線程會執行一些合規性檢查並每30秒運行一次。它現在做一個數據庫查詢。查詢速度很慢(大約需要500毫秒才能返回所有數據),但這沒關係,因爲它不會影響關鍵線程。除非工作線程正在分配內存,否則會導致凍結所有線程的GC。

我聽說所有的庫(包括這個)都不能在啓動後分配內存。不管我是否同意,這是簽署支票的人的要求:)。

現在,很明顯有一些方法可以在沒有分配的情況下將數據導入此過程。我可以設置另一個進程並使用套接字將其連接到此進程。新的.NET 3.5套接字被特別優化,根本不使用新的SocketAsyncEventArgs模式進行分配。 (實際上,我們正在使用它們連接到多個系統,並且從不會看到任何GC。)然後有一個預先分配的字節數組,它從套接字中讀取並遍歷數據,沿途不分配任何字符串。 (我不熟悉.NET中其他形式的IPC,所以我不確定內存映射文件和命名管道是否分配)。

但是,如果有一種更快的方法可以在不經歷所有這些麻煩的情況下完成這個無分配查詢,我更喜歡它。

+0

每隔30秒鐘......你會發現分配對這種長時間段的影響非常非常低。 – Dykam 2010-04-10 21:10:30

+2

嗯,沒有分配。首先從數據庫表中刪除所有字符串。當你完成後回來,我們可以解決問題#2到50.你最終必須切換到C++。 – 2010-04-10 21:31:24

回答

3

您不能重複使用IDataReader(或OdbcDataReaderSqlDataReader或任何同等級別)。它們被設計爲僅與單個查詢一起使用。這些對象封裝了一個單獨的記錄集,所以一旦你獲得並迭代它,它就沒有意義了。

無論如何,創建一個數據讀取器是一個非常便宜的操作,與實際執行查詢的成本相比,它的消耗極小。我看不出這個「沒有分配」要求的邏輯原因。

我會走這麼遠說,這是非常接近不可能改寫庫,以便分配沒有記憶。即使像裝箱整數或使用字符串變量那樣簡單的事情也會分配一些內存。即使它在某種程度上可以重用閱讀器(它不是,正如我所解釋的),它仍然必須再次向數據庫發出查詢,這將需要以準備查詢的形式分配內存,並將其發送通過網絡,再次檢索結果等。

避免內存分配根本不是一個實際的目標。如果確定某些特定操作使用了太多內存,則可能更好地避免使用特定的類型的內存分配。

+0

問題不在於分配數據讀取器本身需要很長時間。正如你所說,它的查詢時間相形見絀。查詢和分配都發生在一個工作線程上,所以我們不關心他們的時間。但隨着時間的推移,「便宜」的分配會導致GC凍結所有線程,包括關鍵線程。根本不可能分配內存。但請參閱例如:http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4215ab9e-4181-4526-823b-d364448188b2 – 2010-04-10 21:20:53

+0

換句話說,目標不是沒有分配。但是在應用程序的連續操作階段沒有分配(啓動完成後)。 – 2010-04-10 21:21:34

+0

@Michael - 但正如你所說,這個查詢是你的「連續操作」的*部分*,每30秒運行一次。該應用程序的性能要求非常嚴格(12,000 TPS!)可能需要對內存分配進行限制,但只要您在該處推送數據庫查詢,就可以將該權利排除在外,查詢將花費的不僅僅是GC通過。 – Aaronaught 2010-04-10 21:29:06

2

對於這樣的需求,你確定像C#這樣的高級語言是你的選擇嗎?
你不能說你正在使用的.NET庫函數是否在內部分配內存。該標準不保證,所以如果他們沒有在當前版本的.NET框架中使用分配,他們可能會在稍後開始。

+0

確實,它並不總是清楚庫函數是否根據其簽名來分配內存。但是你總是可以把圖書館電話放到一個新的項目中,然後做10萬次電話來查看是否有任何GC。儘管如你所說,他們可能會在不同版本的框架中改變它。 C#不是我的選擇,但有些人在C#成功應用程序的連續運行階段嘗試遵循不分配設計模式:http://www.microsoft.com/downloads/details.aspx?displaylang = en&FamilyID = 4215ab9e-4181-4526-823b-d364448188b2 – 2010-04-10 21:09:40

+1

@Michael,這是一個需要在單個實例上每秒處理12,000個事務的項目。如果你把一個數據庫查詢放在那裏,不管它運行得有多快,你都不會做這個基準測試。數據庫查詢是**方式**比內存分配和GC傳遞更昂貴。 – Aaronaught 2010-04-10 21:19:22

+0

@邁克爾:那麼你引用的文件說這種方法包括與MS專家的緊密合作。從我的角度來看,我真的懷疑文章中描述的解決方案將保持無配置,對我而言,它看起來更像是一種破解。那麼,你可以嘗試避免使用庫函數_at所有_...但你的問題是關於數據庫相關的功能,所以我個人懷疑這樣相當複雜的庫函數不會在內部分配。 – Vlad 2010-04-10 21:21:18

1

我建議你剖析應用程序以確定在哪裏花費時間和/或內存。不要猜測 - 你只會猜錯。

+0

是不是像規則3-7的優化? (前兩個是:「不要!」和「不,真的,不!」) – SamB 2010-04-10 22:10:32

+2

@SamB:那實際上是4-8。 3是「你真的不想這麼做,所以在你讓事情變得更糟之前去解決它」。 – 2010-04-10 22:49:00