2010-01-15 24 views
6

मैं .NET चार्ट नियंत्रण लाइब्रेरी का उपयोग कर रहा हूं जो पृष्ठभूमि थ्रेड पर डिस्क पर छवियों को बनाने और सहेजने के लिए .NET 4.0 बीटा 2 के साथ आता है। मैं स्क्रीन पर चार्ट नहीं दिखा रहा हूं, हालांकि, बस एक चार्ट बना रहा हूं, इसे डिस्क पर सहेज रहा हूं, और इसे नष्ट कर रहा हूं। कुछ ऐसा:.NET चार्ट नियंत्रण समांतर प्रदर्शन

public void GeneratePlot(IList<DataPoint> series, Stream outputStream) { 
    using (var ch = new Chart()) { 
     ch.ChartAreas.Add(new ChartArea()); 
     var s = new Series(); 
     foreach (var pnt in series) s.Points.Add(pnt); 
     ch.Series.Add(s); 
     ch.SaveImage(outputStream, ChartImageFormat.Png); 
    } 
} 

प्रत्येक चार्ट को बनाने और सहेजने में लगभग 300 - 400 एमएस लग रहा था। मेरे पास संभावित रूप से सैकड़ों चार्ट बनाने के लिए हैं, इसलिए मैंने सोचा कि मैं इन कार्यों को समानांतर करने के लिए Parallel.For() का उपयोग करूंगा। मेरे पास 8 कोर मशीन है, हालांकि, जब मैं एक समय में 4 चार्ट बनाने की कोशिश करता हूं, तो मेरा चार्ट 800 से 1400 एमएस तक कहीं भी बढ़ता/बचाता है, जिनमें से लगभग Chart.SaveImage तक उपभोग किया जाता है।

मैंने सोचा था कि मैं/हे, इसलिए परीक्षण करने के लिए है कि मैं करने के लिए अंतिम पंक्ति बदल इस डिस्क की एक सीमा हो सकती है:

ch.SaveImage(Stream.Null, ChartImageFormat.Png); 

यहां तक ​​कि एक अशक्त करने के लिए लिख स्ट्रीम प्रदर्शन ही के बारे में अब भी है (800 - 1400 एमएस)।

क्या मुझे इस पुस्तकालय के साथ समानांतर में पृष्ठभूमि धागे पर छवियां नहीं बनाना चाहिए, या क्या मैं कुछ गलत कर रहा हूं?

धन्यवाद

संपादित करें: जोड़ा गया पूरा कोड नमूना

सीधे शब्दों में झंडा CreateCharts() के लिए पारित बनाम धारावाहिक समानांतर परीक्षण करने के लिए बदल जाते हैं।

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms.DataVisualization.Charting; 

namespace ConsoleChartTest 
{ 
    class Program 
    { 
     public static void GeneratePlot(IEnumerable<DataPoint> series, Stream outputStream) 
     { 
      long beginTime = Environment.TickCount; 

      using (var ch = new Chart()) 
      { 
       ch.ChartAreas.Add(new ChartArea()); 
       var s = new Series(); 
       foreach (var pnt in series) 
        s.Points.Add(pnt); 
       ch.Series.Add(s); 

       long endTime = Environment.TickCount; 
       long createTime = endTime - beginTime; 

       beginTime = Environment.TickCount; 
       ch.SaveImage(outputStream, ChartImageFormat.Png); 
       endTime = Environment.TickCount; 
       long saveTime = endTime - beginTime; 

       Console.WriteLine("Thread Id: {0,2} Create Time: {1,3} Save Time: {2,3}", 
        Thread.CurrentThread.ManagedThreadId, createTime, saveTime); 
      } 
     } 

     public static void CreateCharts(bool parallel) 
     { 
      var data = new DataPoint[20000]; 
      for (int i = 0; i < data.Length; i++) 
      { 
       data[i] = new DataPoint(i, i); 
      } 

      if (parallel) 
      { 
       Parallel.For(0, 10, (i) => GeneratePlot(data, Stream.Null)); 
      } 
      else 
      { 
       for (int i = 0; i < 10; i++) 
        GeneratePlot(data, Stream.Null); 
      } 
     } 

     static void Main(string[] args) 
     { 
      Console.WriteLine("Main Thread Id: {0,2}", Thread.CurrentThread.ManagedThreadId); 

      long beginTime = Environment.TickCount; 
      CreateCharts(false); 
      long endTime = Environment.TickCount; 
      Console.WriteLine("Total Time: {0}", endTime - beginTime); 
     } 
    } 
} 
+0

हास्य हमें - आप सहित पूरा कोड पोस्ट कर सकते हैं, जहां आप 'Parallel.For' का उपयोग करें? और हमें यह भी बताएं कि आप इस कोड का उपयोग कैसे कर रहे हैं, जहां संख्याएं आ रही हैं? आपके बेंचमार्किंग के दौरान सीपीयू उपयोग कैसा दिखता है? – Aaronaught

+0

शायद समस्या रूपांतरण में है, फिर भी आप और कोड पोस्ट कर सकते हैं? –

उत्तर

3

आप System.Drawing नामस्थान के साथ समस्याएं चला रहे हैं। वहां कुछ भारी धागे लॉकिंग हैं जो कुछ कार्यों को क्रमबद्ध करेंगे। जब तक आप Chart.SaveImage() पर कॉल नहीं करते हैं, तब तक यह वास्तव में छवि प्रस्तुत करता है, यही वह समय है जो आपका पूरा समय खा रहा है।

यदि आप अपना परीक्षण प्रोग्राम थोड़ा सा बदलते हैं तो आप समांतरता को देख सकते हैं, लेकिन ग्राफिक्स ड्राइंग कोड के अंदर लॉकिंग से इसे गंभीर रूप से बाधित किया जा रहा है।

मुख्य विधि में count = 50 के साथ खिलौना के आसपास खिलौना ... एक ही समय में दोनों आउटपुट देखकर मुझे लगता है कि, आप देख सकते हैं कि समांतर एक लगातार तेज़ है, हालांकि यह लॉकिंग के कारण रैखिक रूप से स्केल नहीं करता है ड्राइंग नाम स्थान में:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.IO; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms.DataVisualization.Charting; 

namespace ConsoleChartTest 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     var count = 50; 
     Console.WriteLine("Serial Test Start, Count: {0}"); 
     Console.WriteLine("Main Thread Id: {0,2}", Thread.CurrentThread.ManagedThreadId); 

     var sw = new Stopwatch(); 
     sw.Start(); 
     CreateCharts(count, false); 
     sw.Stop(); 
     Console.WriteLine("Total Serial Time: {0}ms", sw.ElapsedMilliseconds); 

     Console.WriteLine("Parallel Test Start"); 
     Console.WriteLine("Main Thread Id: {0,2}", Thread.CurrentThread.ManagedThreadId); 

     sw.Restart(); 
     CreateCharts(count, true); 
     sw.Stop(); 
     Console.WriteLine("Total Parallel Time: {0}ms", sw.ElapsedMilliseconds); 
    } 

    public static void GeneratePlot(IEnumerable<DataPoint> series, Stream outputStream) 
    { 
     var sw = new Stopwatch(); 
     sw.Start(); 

     var ch = new Chart(); 
     ch.ChartAreas.Add(new ChartArea()); 
     var s = new Series(); 
     foreach(var pnt in series) s.Points.Add(pnt); 
     ch.Series.Add(s); 

     sw.Stop(); 
     long createTime = sw.ElapsedMilliseconds; 
     sw.Restart(); 

     ch.SaveImage(outputStream, ChartImageFormat.Png); 
     sw.Stop(); 

     Console.WriteLine("Thread Id: {0,2} Create Time: {1,3}ms Save Time: {2,3}ms", 
      Thread.CurrentThread.ManagedThreadId, createTime, sw.ElapsedMilliseconds); 
    } 

    public static void CreateCharts(int count, bool parallel) 
    { 
     var data = new DataPoint[20000]; 
     if (parallel) 
     { 
     Parallel.For(0, data.Length, (i) => data[i] = new DataPoint(i, i)); 
     Parallel.For(0, count, (i) => GeneratePlot(data, Stream.Null)); 
     } 
     else 
     { 
     for (int i = 0; i < data.Length; i++) 
      data[i] = new DataPoint(i, i); 
     for (int i = 0; i < count; i++) 
      GeneratePlot(data, Stream.Null); 
     } 
    } 
    } 
} 

क्या चल रहा ताला लगा है है Chart.SaveImage() ->ChartImage.GetImage() ->ChartPicture.Paint()

+0

क्या कोई तरीका है कि आप इस बाधा के आसपास जाने के बारे में जानते हैं? – dewald

+0

@dewald - सीधे नहीं, हालांकि कुछ तृतीय पक्ष विकल्प हो सकते हैं जो 'System.Drawing' का उपयोग नहीं करते हैं (मुझे लगता है कि सॉफ्टवेयरएफएक्स अपने इंजन का उपयोग करता है, लेकिन यह सस्ता नहीं है)। हम उम्मीद कर सकते हैं कि वे 4.0 आरसी/आरटीएम में थ्रेडिंग में सुधार करेंगे लेकिन ऐसा प्रतीत नहीं होता है।खेद है कि जवाब बेकार है, लेकिन मेरे विचार से यह ड्रॉइंग नेमस्पेस अंधेरे युग में छोड़ा गया है। –

0

शायद तुम एक बीएमपी, जो और अधिक डिस्क स्थान ले जाएगा के रूप में छवि को बचा सकता है, लेकिन यह करने के लिए की आवश्यकता होगी प्रसंस्करण की राशि में कटौती करेगा। संपीड़न समस्याएं पैदा कर रहा है या नहीं, यह देखने के लिए आपको विभिन्न छवि प्रारूपों का प्रयास करना चाहिए। यदि ऐसा है, तो आप संपीड़न करने के बाद कुछ अन्य धागे को स्पिन करना चाहेंगे।

+0

यह उत्तर नहीं देता है कि यह समान क्यों प्रतीत नहीं होता है। – Dykam

+0

यह समानांतर में जा सकता है, लेकिन यदि आप कंप्यूटर बहुत अधिक स्विचिंग कर रहे हैं, तो चीजें वास्तव में धीमी हो सकती हैं। शायद पीएनजी एन्कोडर पहले से ही हुड के नीचे समानांतर में चलता है, और इसके समानांतर उदाहरण चलाने की कोशिश करने से आपकी मशीन को संदर्भ में बहुत अधिक स्विच करने के कारण बहुत सारे धागे पैदा होते हैं। कई धागे की तुलना में, 1 थ्रेड के साथ चलते समय आपका प्रोसेसर उपयोग कैसा दिखता है? क्या यह पहले से ही 100% पर 1 धागा है? – Kibbee

+0

मैंने बीएमपी (अन्य सभी प्रारूपों के साथ) की कोशिश की, लेकिन यह वास्तव में समानांतर प्रदर्शन को प्रभावित नहीं करता था। – dewald

0

याद रखें, आपके पास हाइपर-थ्रेडिंग और वास्तव में कोर हैं। आपको इसके बारे में सावधान रहना चाहिए, हाइपर-थ्रेडिंग में कोर के समान प्रदर्शन नहीं होता है।

अन्य बात है, एक अच्छा सौदा समानांतर को क्रियान्वित करने के साथ काम करने के लिए आप की तरह

MaxThreads = कोर धागे की एक अधिकतम संख्या निर्धारित करना चाहिए जब आप अपने पूल धागा बनाने है - 2;

जब मैं कोर कहता हूं, कोर को हाइपर-थ्रेडिंग कोर नहीं पढ़ते हैं।

1 - ओएस 1 - मुख्य अनुप्रयोग एक्स - प्रक्रिया करने के लिए कोर।

यदि आप प्रोसेसर में सहमति के कारण बहुत अधिक धागे बनाते हैं तो आप प्रदर्शन खो देंगे।

जेपीईजी या पीएनजी छवियां बनाएं अन्य अच्छी बात है, इस तरह आप छवि को सहेजते समय एचडी पर कम समय ले लेंगे। जेपीईजी और पीएनजी की गुणवत्ता के बारे में भी ख्याल रखना, 'कारण यह 100% है तो यह बड़ा हो सकता है।

अन्य बिंदु जो प्रासंगिक है। आपको एचडी पर सहमति होगी, 'कारण इस पर अभिलेखागार बनाने वाले बहुत सारे धागे होंगे। आप इसके बारे में क्या कर सकते हैं? यह वास्तव में हल करने में कठिन समस्या है क्योंकि हमारे पास समानांतर एचडी नहीं है। इसलिए, आप अन्य थ्रेड की तरह इमेज बफर भेजने के लिए एक जगह बना सकते हैं, जो कुछ भी संसाधित नहीं करता है, बस छवियों के बफर को प्राप्त करना और उदाहरण के लिए इसे आंतरिक सूची में संग्रहीत करना। और 5 एम 5 सेकंड में (या कुछ स्थितियां जो आपको लगता है कि यह बेहतर है), यह एचडी पर चित्र लिखना शुरू कर देता है। तो आपके पास एक धागा होगा "बिना" सहमति के एचडी पर काम करेगा, और अन्य धागे सिर्फ छवियों को संसाधित करने के लिए।

पर।

+0

@ एसएसीआई - यह एक एचडी मुद्दा नहीं है क्योंकि मैं स्ट्रीम.इन पर लिखकर इसका परीक्षण कर रहा हूं, इसलिए यह कभी भी एचडी को छूता नहीं है। मैंने धागे की अधिकतम संख्या को 4 तक कम करने की कोशिश की (क्योंकि मैं 8 कोर मशीन पर हूं), लेकिन यह मदद नहीं कर रहा था। – dewald

0

अगर मुझे लगता है कि आईडी को लगता है कि यह SaveImage के अंदर कोड की तरह दिखता है तो क्रिटिकलसेक्शन या लॉक द्वारा संरक्षित किया जाता है, जो उस कोड के कुछ हिस्सों में चलाने के लिए केवल एक थ्रेड को अनुमति देता है।

तो, आप पृष्ठभूमि धागे का उपयोग करने की अनुमति नहीं देने के बारे में सही हो सकते हैं, लेकिन मुझे लगता है कि आपको एक समय में SaveImage के अंदर 1 से अधिक धागे चलने की अनुमति नहीं है। इस समारोह पर दस्तावेज बहुत अस्पष्ट है, लेकिन समय बहुत ही सुझावशाली हैं। 4 चार्ट 1 चार्ट के रूप में लगभग 4 गुना लंबा लेते हैं।

यदि आप पृष्ठभूमि धागे का उपयोग करके केवल 1 चार्ट सहेजते हैं - क्या यह पूरी गति से चलता है?

संबंधित मुद्दे