我使用gpars並行處理250M行的MySQL數據庫表。我創建了8個gpars線程,8個獨立的數據庫連接,並以這樣一種方式劃分數據,即每個線程獨立運行在不同的行數範圍內......這是一種便宜的MapReduce概念。在覈心,邏輯是這樣的:groovy應用與gpars在很多迭代後變慢
withExistingPool(pool)
{
connection_array.collectParallel()
{
// Figure out which connection this thread can use.
// We use the index into the array to figure out
// which thread we are, and this tells us where to
// read data.
int i
for (i = 0; i < connection_array.size(); i++)
if (it == connection_array[i])
break
// Each thread runs the same query, with LIMIT controlling
// the position of rows it will read...if we have 8 threads
// reading 40000 rows per call to this routine, each thread
// reads 5000 rows (thread-0 reads rows 0-4999, thread-1 reads
// 5000-9999 and so forth).
def startrow = lastrow + (i * MAX_ROWS)
def rows = it.rows("SELECT * ... LIMIT ($startrow, $MAX_ROWS)")
// Add our rows to the result set we will return to the caller
// (needs to be serialized since many threads can be here)
lock.lock()
if (!result)
result = rows
else
result += rows
lock.unlock()
}
}
該代碼最初工作得很好,每秒啓動時超過10,000行。但是在幾百萬行之後,它開始減速。當我們有2500萬行,而不是每秒10000行時,我們每秒只能獲得1,000行。如果我們終止應用程序並從我們停止的地方重新啓動應用程序,它會再次回到每秒10K行一段時間,但隨着處理的繼續,它會一直減慢。
有大量的處理能力可用 - 這是一個8路系統和數據庫是在網絡上,所以有等待時間公平一點不管。處理器運行時一般不會超過25-30%的繁忙時間。也似乎沒有任何內存泄漏 - 我們監視內存統計信息,並且在處理進行之後看不到任何更改。 MySQL服務器似乎沒有被強調(它最初運行的時候大約佔30%,隨着應用程序的減速而下降)。
是否有任何技巧可以幫助這類事物在大量迭代中更一致地運行?
這可能是因爲你不斷調整結果列表的大小。你有沒有嘗試指定一個初始大小的結果?你不會顯示它的初始化方式/你在哪裏初始化 –
你也可以使用'(0 ..
@ tim - 感謝您的建議......您的第一條評論是一個很好的評論 - 因爲我們知道有多少行被提取,所以我們可以預先分配結果並將其作爲參數傳遞,而不是每次動態構建它。這幫助了近5%的表現。第二個建議實際上比我們原來的方法慢了一點 - 我想這不需要很長時間就可以搜索一個8項數組。不幸的是,最初的問題仍然存在......例程越來越慢越多的記錄它處理。 –