पर आप बहुत सारे धागे बना रहे हैं। न केवल धागे बनाने के लिए महंगा है, लेकिन सीपीयू बाध्य अनुप्रयोग के लिए, आप उपलब्ध प्रोसेसर के मुकाबले ज्यादा धागे नहीं चाहते हैं (यदि आप करते हैं, तो आपको थ्रेड के बीच प्रोसेसिंग पावर स्विचिंग खर्च करना पड़ता है, जो कैश का कारण बनने की संभावना है मिस जो बहुत महंगा हैं)।
execute
पर धागा भेजने के लिए भी अनावश्यक है; इसकी सभी जरूरतों को Runnable
है। आप इन परिवर्तनों को लागू करके एक बड़ा प्रदर्शन को बढ़ावा देने की जाएगी:
ExecutorService
एक स्थिर सदस्य बनाने, यह आकार वर्तमान प्रोसेसर के लिए, और यह एक ThreadFactory
तो यह main
के बाद चल रहे प्रोग्राम नहीं रखता भेज पूरा कर दिया है। (यह शायद एक स्थिर क्षेत्र के रूप में यह ध्यान में रखते हुए बजाय विधि के लिए एक पैरामीटर के रूप में यह भेजने के लिए वास्तुकला क्लीनर होगा, मैं छोड़ कि पाठक के लिए एक व्यायाम ☺ के रूप में।)
private static final ExecutorService workerPool =
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});
MatrixThread
Runnable
लागू नहीं बल्कि बनाओ Thread
के उत्तराधिकारी से। धागे बनाने के लिए महंगी हैं; पीओजेओ बहुत सस्ते हैं। आप इसे static
भी बना सकते हैं जो उदाहरणों को छोटा बनाता है (क्योंकि गैर स्थैतिक वर्ग संलग्न वस्तु के लिए एक निहित संदर्भ प्राप्त करते हैं)।
private static class MatrixThread implements Runnable
- परिवर्तन से
(1), आप अब awaitTermination
कोई यकीन है कि सभी कार्य समाप्त कर रहे हैं (इस कार्यकर्ता पूल के रूप में) बनाने के लिए कर सकते हैं।इसके बजाय, submit
विधि का उपयोग करें जो Future<?>
देता है। किसी भी सूची में सभी भावी वस्तुओं को एकत्रित करें, और जब आप सभी कार्यों को सबमिट करते हैं, तो सूची में पुनरावृत्त करें और प्रत्येक ऑब्जेक्ट के लिए get
पर कॉल करें।
public Matrix multiply(Matrix multiplier) throws InterruptedException {
Matrix result = new Matrix(dimension);
List<Future<?>> futures = new ArrayList<Future<?>>();
for(int currRow = 0; currRow < multiplier.dimension; currRow++) {
for(int currCol = 0; currCol < multiplier.dimension; currCol++) {
Runnable worker = new MatrixThread(this, multiplier, currRow, currCol, result);
futures.add(workerPool.submit(worker));
}
}
for (Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException e){
throw new RuntimeException(e); // shouldn't happen, but might do
}
}
return result;
}
यह एकल पिरोया संस्करण की तुलना में तेजी हो जाएगा:
आपका multiply
विधि अब कुछ इस तरह देखना चाहिए? खैर, मेरे तर्कसंगत क्रैपी बॉक्स पर मल्टीथ्रेड संस्करण n
< 1024.
के मूल्यों के लिए धीमा है, हालांकि यह सतह को खरोंच कर रहा है। अपनी स्मृति की खपत O(n²)
है, जो एक बहुत बुरा संकेत है - असली समस्या यह है कि आप एक बहुत MatrixThread
की उदाहरण बना है। MatrixThread.run
में लूप को आंतरिक स्थानांतरित करने से craploads (आदर्श रूप से, आप कार्यकर्ता धागे की तुलना में अधिक कार्य नहीं बनाते) के प्रदर्शन में सुधार करेंगे।
संपादित करें: मैं अधिक दबाव काम करने के लिए है के रूप में, मैं विरोध इस आगे के अनुकूलन नहीं कर सका। मैं इस के साथ आया था (... कोड की horrendously बदसूरत टुकड़ा) है कि "केवल" O(n)
नौकरियों बनाता है:
public Matrix multiply(Matrix multiplier) throws InterruptedException {
Matrix result = new Matrix(dimension);
List<Future<?>> futures = new ArrayList<Future<?>>();
for(int currRow = 0; currRow < multiplier.dimension; currRow++) {
Runnable worker = new MatrixThread2(this, multiplier, currRow, result);
futures.add(workerPool.submit(worker));
}
for (Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException e){
throw new RuntimeException(e); // shouldn't happen, but might do
}
}
return result;
}
private static class MatrixThread2 implements Runnable
{
private Matrix self, mul, result;
private int row, col;
private MatrixThread2(Matrix a, Matrix b, int row, Matrix result)
{
this.self = a;
this.mul = b;
this.row = row;
this.result = result;
}
@Override
public void run()
{
for(int col = 0; col < mul.dimension; col++) {
int cellResult = 0;
for (int i = 0; i < self.getMatrixDimension(); i++)
cellResult += self.template[row][i] * mul.template[i][col];
result.template[row][col] = cellResult;
}
}
}
यह अभी भी महान नहीं है, लेकिन मूल रूप से मल्टी-थ्रेडेड संस्करण कुछ भी गणना कर सकता है आप रोगी हो जाएगा प्रतीक्षा करने के लिए पर्याप्त है, और यह एकल-थ्रेडेड संस्करण से तेज़ कर देगा।
आपके कोड में "गुणा करें" विधि –
गुम है क्यों आप इस तरह कुछ मल्टीथ्रेड करेंगे? यह पूरी तरह से सीपीयू-बाध्य है, ऐसा नहीं है कि आपके पास थ्रेड अवरुद्ध है I/O के लिए प्रतीक्षा कर रहा है। –
मल्टीथ्रेडिंग ठीक काम कर सकती है, लेकिन यह कितनी सीपीयू पर निर्भर करती है (10x10 10x10 द्वारा गुणा करें आपके उदाहरण में 100 धागे बनाता है ... आपके पास केवल 2-8 सीपीयू है) और मैट्रिस कितने बड़े हैं (क्या वे फिट हैं एल 2/एल 3 कैश?)। एमकेएल और ओपनसीएल जैसे मूल पुस्तकालय इस का एक बेहतर काम करते हैं। – basszero