निम्नलिखित नूनिट परीक्षण एक एकल थ्रेड चलाने के बीच प्रदर्शन को दोहरी कोर मशीन पर चलने वाले 2 धागे चलाने के बीच तुलना करता है। विशेष रूप से, यह एक वीएमवेयर डुअल कोर वर्चुअल विंडोज 7 मशीन है जो क्वाड कोर लिनक्स एसएलडीडी होस्ट पर चल रही है, जिसमें डेल इंस्पेरन 503 है।दोहरे कोर प्रदर्शन एकल कोर से भी बदतर है?
प्रत्येक थ्रेड बस 2 काउंटर, एडकॉन्टर और रीड काउंटर को लूप और बढ़ाता है। यह परीक्षण एक क्यूई कार्यान्वयन का मूल परीक्षण था जिसे बहु-कोर मशीन पर खराब प्रदर्शन करने के लिए खोजा गया था। तो समस्या को छोटे प्रतिलिपिबद्ध कोड में कम करने में, आपके पास कोई कतार केवल बढ़ती चर और सदमे और निराशा के लिए है, यह 2 धागे के साथ बहुत धीमी है।
पहला परीक्षण चलाते समय, टास्क मैनेजर कोर के 1% को अन्य कोर के साथ लगभग 100% व्यस्त दिखाता है। सिंगल थ्रेड टेस्ट के लिए टेस्ट आउटपुट यहां दिया गया है:
readCounter 360687000
readCounter2 0
total readCounter 360687000
addCounter 360687000
addCounter2 0
आप 360 मिलियन से अधिक वेतन वृद्धि देखते हैं!
अगला दोहरी धागा परीक्षण परीक्षण के पूरे 5 सेकंड की अवधि के लिए दोनों कोरों पर 100% व्यस्त दिखाता है। लेकिन यह उत्पादन पता चलता है केवल:
readCounter 88687000
readCounter2 134606500
totoal readCounter 223293500
addCounter 88687000
addCounter2 67303250
addFailure0
केवल 223 मिलियन पढ़ने वेतन वृद्धि है कि। भगवान की सृष्टि क्या है उन 2 सीपीयू कम काम करने के लिए उन 5 सेकंड के लिए कर रहे हैं?
कोई संभावित सुराग? और क्या आप यह देखने के लिए अपनी मशीन पर परीक्षण चला सकते हैं कि आपको अलग-अलग परिणाम मिलते हैं या नहीं? एक विचार यह है कि शायद वीएमवेयर डुअल कोर प्रदर्शन वह नहीं है जो आप उम्मीद करेंगे।
using System;
using System.Threading;
using NUnit.Framework;
namespace TickZoom.Utilities.TickZoom.Utilities
{
[TestFixture]
public class ActiveMultiQueueTest
{
private volatile bool stopThread = false;
private Exception threadException;
private long addCounter;
private long readCounter;
private long addCounter2;
private long readCounter2;
private long addFailureCounter;
[SetUp]
public void Setup()
{
stopThread = false;
addCounter = 0;
readCounter = 0;
addCounter2 = 0;
readCounter2 = 0;
}
[Test]
public void TestSingleCoreSpeed()
{
var speedThread = new Thread(SpeedTestLoop);
speedThread.Name = "1st Core Speed Test";
speedThread.Start();
Thread.Sleep(5000);
stopThread = true;
speedThread.Join();
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
Console.Out.WriteLine("readCounter " + readCounter);
Console.Out.WriteLine("readCounter2 " + readCounter2);
Console.Out.WriteLine("total readCounter " + (readCounter + readCounter2));
Console.Out.WriteLine("addCounter " + addCounter);
Console.Out.WriteLine("addCounter2 " + addCounter2);
}
[Test]
public void TestDualCoreSpeed()
{
var speedThread1 = new Thread(SpeedTestLoop);
speedThread1.Name = "Speed Test 1";
var speedThread2 = new Thread(SpeedTestLoop2);
speedThread2.Name = "Speed Test 2";
speedThread1.Start();
speedThread2.Start();
Thread.Sleep(5000);
stopThread = true;
speedThread1.Join();
speedThread2.Join();
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
Console.Out.WriteLine("readCounter " + readCounter);
Console.Out.WriteLine("readCounter2 " + readCounter2);
Console.Out.WriteLine("totoal readCounter " + (readCounter + readCounter2));
Console.Out.WriteLine("addCounter " + addCounter);
Console.Out.WriteLine("addCounter2 " + addCounter2);
Console.Out.WriteLine("addFailure" + addFailureCounter);
}
private void SpeedTestLoop()
{
try
{
while (!stopThread)
{
for (var i = 0; i < 500; i++)
{
++addCounter;
}
for (var i = 0; i < 500; i++)
{
readCounter++;
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
private void SpeedTestLoop2()
{
try
{
while (!stopThread)
{
for (var i = 0; i < 500; i++)
{
++addCounter2;
i++;
}
for (var i = 0; i < 500; i++)
{
readCounter2++;
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
}
}
संपादित करें: मैं ऊपर एक क्वाड-कोर लैपटॉप पर w/ओ VMware परीक्षण किया है और इसी तरह की अवक्रमित प्रदर्शन मिला है। इसलिए मैंने उपर्युक्त के समान एक और परीक्षण लिखा लेकिन प्रत्येक थ्रेड विधि को एक अलग वर्ग में रखा गया है। ऐसा करने का मेरा उद्देश्य 4 कोर का परीक्षण करना था।
वैसे परीक्षण ने उत्कृष्ट परिणामों को दिखाया जो लगभग 1, 2, 3, या 4 कोर के साथ लगभग रैखिक रूप से सुधार हुआ।
कुछ प्रयोगों के साथ अब दोनों मशीनों पर ऐसा लगता है कि उचित प्रदर्शन केवल तभी होता है जब मुख्य थ्रेड विधियां एक ही उदाहरण के बजाय अलग-अलग उदाहरणों पर हों।
दूसरे शब्दों में, यदि किसी विशेष वर्ग के एक ही उदाहरण पर एकाधिक धागे मुख्य प्रविष्टि विधि, तो आपके द्वारा जोड़े गए प्रत्येक थ्रेड के लिए बहु-कोर पर प्रदर्शन खराब होगा, जैसा कि आप मान सकते हैं।
यह लगभग प्रतीत होता है कि सीएलआर "सिंक्रनाइज़िंग" है, इसलिए उस समय केवल एक थ्रेड उस विधि पर चल सकता है। हालांकि, मेरा परीक्षण कहता है कि यह मामला नहीं है। तो यह अभी भी अस्पष्ट है कि क्या हो रहा है।
लेकिन मेरी खुद की समस्या को थ्रेड को अपने प्रारंभिक बिंदु के रूप में चलाने के तरीकों के अलग-अलग उदाहरण बनाकर हल किया जाना प्रतीत होता है।
निष्ठा से, वेन
संपादित करें:
यहाँ एक अद्यतन इकाई परीक्षण है कि एक वर्ग का एक ही उदाहरण पर 1, 2, 3, 4 & उन सभी के साथ धागे का परीक्षण करती है। चर के साथ सरणी का उपयोग थ्रेड लूप में कम से कम 10 तत्वों के अलावा उपयोग करता है। और प्रदर्शन अभी भी प्रत्येक थ्रेड के लिए महत्वपूर्ण रूप से घटता है।
using System;
using System.Threading;
using NUnit.Framework;
namespace TickZoom.Utilities.TickZoom.Utilities
{
[TestFixture]
public class MultiCoreSameClassTest
{
private ThreadTester threadTester;
public class ThreadTester
{
private Thread[] speedThread = new Thread[400];
private long[] addCounter = new long[400];
private long[] readCounter = new long[400];
private bool[] stopThread = new bool[400];
internal Exception threadException;
private int count;
public ThreadTester(int count)
{
for(var i=0; i<speedThread.Length; i+=10)
{
speedThread[i] = new Thread(SpeedTestLoop);
}
this.count = count;
}
public void Run()
{
for (var i = 0; i < count*10; i+=10)
{
speedThread[i].Start(i);
}
}
public void Stop()
{
for (var i = 0; i < stopThread.Length; i+=10)
{
stopThread[i] = true;
}
for (var i = 0; i < count * 10; i += 10)
{
speedThread[i].Join();
}
if (threadException != null)
{
throw new Exception("Thread failed: ", threadException);
}
}
public void Output()
{
var readSum = 0L;
var addSum = 0L;
for (var i = 0; i < count; i++)
{
readSum += readCounter[i];
addSum += addCounter[i];
}
Console.Out.WriteLine("Thread readCounter " + readSum + ", addCounter " + addSum);
}
private void SpeedTestLoop(object indexarg)
{
var index = (int) indexarg;
try
{
while (!stopThread[index*10])
{
for (var i = 0; i < 500; i++)
{
++addCounter[index*10];
}
for (var i = 0; i < 500; i++)
{
++readCounter[index*10];
}
}
}
catch (Exception ex)
{
threadException = ex;
}
}
}
[SetUp]
public void Setup()
{
}
[Test]
public void SingleCoreTest()
{
TestCores(1);
}
[Test]
public void DualCoreTest()
{
TestCores(2);
}
[Test]
public void TriCoreTest()
{
TestCores(3);
}
[Test]
public void QuadCoreTest()
{
TestCores(4);
}
public void TestCores(int numCores)
{
threadTester = new ThreadTester(numCores);
threadTester.Run();
Thread.Sleep(5000);
threadTester.Stop();
threadTester.Output();
}
}
}
क्या आप इसे डिबगर संलग्न किए बिना रिलीज़ मोड में चला रहे हैं? –
नोट: आपके कोड में कोई थ्रेड सिंक्रनाइज़ेशन ऑपरेशन नहीं है (ताले या इंटरलॉक या कुछ और)। यदि आप इसे पसंद करते हैं तो आप सभी मानों के लिए रैंडम का उपयोग भी कर सकते हैं क्योंकि बिना सिंक्रनाइज़ेशन के मल्टीथ्रेड कोड को सही तरीके से चलाने का कोई तरीका नहीं है। –
जिम, मैं इसे दोनों तरीकों से आजमाया गया हूं। लेकिन चर्चा की गई संख्या डीबग मोड के दौरान होती है। एलेक्सेल..मैं ताले और interleaved की जरूरत के बारे में पता है। बेशक। लेकिन यह सिर्फ प्रयोगात्मक कोड है। प्रयोग ताले के साथ शुरू हुआ लेकिन प्रदर्शन भयानक था - अधिक धागे/कोर के साथ बदतर। इसलिए मैंने ताले को यह देखने के लिए हटा दिया कि यह तेज है या नहीं। नहीं ... अभी भी बुरा है। तो मैं अलग करने की कोशिश कर रहा हूं क्यों 4 कोर एक ही कोड चल रहे हैं w/o किसी भी ताले तो कुत्ते धीमा ??? तुम जानते हो क्यों? – Wayne