Timmey92
Commodore
- Registriert
- Okt. 2008
- Beiträge
- 4.567
Moin!
Habe mich aus Mathematischem Interesse dazu entschlossen mal einen Monte-Carlo Algorithmus zu programmieren um eine Annäherung an PI zu berechnen.
Leider laste ich nur 25% meiner CPU aus derzeit (QuadCore) und möchte für eine schnellere ausführungsgeschwindigkeit Threading einführen. Habe damit aber bisher noch nicht gearbeitet (bzw. nur kleinere Sachen mal ausgelagert, kaum Erfahrung wie man das praktisch einsetzt).
Momentan nutze ich einen Thread Pool und füge da ganz viele kleine Threads zu (für jeden einzelnen Punkt ein Thread, bzw. eine Aufgabe in der ThreadPool Queue). Da friert mir bei längeren Berechnungen mit Millionen Punkten der UI-Thread ein.
Vielleicht habt ihr ja Lösungs/Verbesserungsvorschläge?
Freue mich über eure Hilfe!
Projektmappe gibts hier (VS 2010 Ultimate):
http://filebeam.com/ab953eb4740c1d7984cee5ac699d442c
Hier der Code:
Neuster Code mit Background Workern.
Ich glaube mein Fehler ist einfach das ich den UI Thread zu sehr fordere mit dem Neuzeichnen.
Wo und WIE kann ich noch Sachen aus dem UI Thread auslagern, damit der nicht mehr blockiert?
Habe mich aus Mathematischem Interesse dazu entschlossen mal einen Monte-Carlo Algorithmus zu programmieren um eine Annäherung an PI zu berechnen.
Leider laste ich nur 25% meiner CPU aus derzeit (QuadCore) und möchte für eine schnellere ausführungsgeschwindigkeit Threading einführen. Habe damit aber bisher noch nicht gearbeitet (bzw. nur kleinere Sachen mal ausgelagert, kaum Erfahrung wie man das praktisch einsetzt).
Momentan nutze ich einen Thread Pool und füge da ganz viele kleine Threads zu (für jeden einzelnen Punkt ein Thread, bzw. eine Aufgabe in der ThreadPool Queue). Da friert mir bei längeren Berechnungen mit Millionen Punkten der UI-Thread ein.
Vielleicht habt ihr ja Lösungs/Verbesserungsvorschläge?
Freue mich über eure Hilfe!
Projektmappe gibts hier (VS 2010 Ultimate):
http://filebeam.com/ab953eb4740c1d7984cee5ac699d442c
Hier der Code:
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
namespace Monte_Carlo_Visualisierung
{
public partial class Form1 : Form
{
List<Point> pointList = new List<Point>();
bool running = false;
Random Rand = new Random(); //Zufallsgenerator
Bitmap picture = new Bitmap(500, 500);
Graphics g;
Pen bigPen = new Pen(Color.Black, 4); //Farbe + Stärke
Pen smallPen = new Pen(Color.Black, 2);
Pen pointPenIn = new Pen(Color.Red, 1);
Pen pointPenOut = new Pen(Color.Blue, 1);
Size small = new Size(1, 1);
int maxPoints = 10; //Wieviele Punkte dürfen höchstens geworfen werden
int currentPoints = 0; //Alle gezeichneten Punkte
int hitPoints = 0; //Punkte im Kreis
int failPoints = 0; //Punkte außerhalb des Kreises
int sleepTime = 0;
/*
Ultraschnell (0ms)
Wie im Fluge (1ms)
Sehr schnell (50ms)
Schnell (100ms)
Normal (250ms)
Langsam (500ms)
Sehr Langsam (1000ms)
Slow Motion (3 Sekunden)
*/
public Form1()
{
InitializeComponent();
g = Graphics.FromImage(picture);
DrawBasis();
comboBox1.SelectedItem = comboBox1.Items[0];
}
//Box und den Kreis zeichnen, einfärben
private void DrawBasis()
{
picture = new Bitmap(500, 500);
g = Graphics.FromImage(picture);
picture.MakeTransparent();
//Box zeichnen
Rectangle box = new Rectangle(0, 0, 500, 500);
SolidBrush brushWhite = new SolidBrush(Color.Gray);
SolidBrush brushNavy = new SolidBrush(Color.Turquoise);
//Box zeichnen und einfärben
g.DrawRectangle(bigPen, box);
g.FillRectangle(brushWhite, box);
//Kreis zeichnen und einfärben
g.DrawEllipse(smallPen, box);
g.FillEllipse(brushNavy, box);
pictureBox1.Image = picture;
pictureBox1.Refresh();
}
private void tbInterval_KeyPress(object sender, KeyPressEventArgs e)
{
//akzeptiere nur Zahlen (Zeit ist in Millisekunden)
if (!Char.IsDigit(e.KeyChar))
e.Handled = true;
}
enum waitTime { ultra = 0, wif = 1, sschnell = 50, schnell = 100, normal = 250, langsam = 500, slangsam = 1000, slowmo = 3000 };
private void btnStart_Click(object sender, EventArgs e)
{
//keine aktiven Worker = Start Button
if (running == false)
{
running = true;
//Zurücksetzen auf 0
DrawBasis();
maxPoints = Int32.Parse(nupPointNumber.Text);
pointList.Clear();
//Zähler auf 0
currentPoints = 0;
hitPoints = 0;
failPoints = 0;
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
btnStart.Text = "Stop";
nupPointNumber.ReadOnly = true;
bgw.RunWorkerAsync();
}
//aktive Worker = Stop Button
else
{
// DrawBasis();
running = false;
btnStart.Text = "Start";
nupPointNumber.ReadOnly = false;
}
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
while (currentPoints < maxPoints)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(calcPoint));
currentPoints++; //Zähler der Punkte erhöhen
}
running = false;
}
private void calcPoint(object arguments)
{
Thread.Sleep(sleepTime);
Point p1 = new Point(Rand.Next(500), Rand.Next(500));
Point m = new Point(250, 250); //mittelpunkt
//Entfernung von p1 zu m darf nicht mehr als 250 pixel betragen, sonst außerhalb des Kreises
float d = (float)Math.Sqrt((p1.X - m.X) * (p1.X - m.X) + (p1.Y - m.Y) * (p1.Y - m.Y));
if (d < 250)
hitPoints++; //Abstand kleienr als 250 -> innerhalb des Kreises, Zähler erhöhen
else
failPoints++; //Abstand größer als 250 -> außerhalb des Kreises, Zähler erhöhen
try
{
this.Invoke(new ImageDelegate(drawPoint), p1);
}
catch
{
return;
}
}
public delegate void ImageDelegate(object a);
private void drawPoint(object a)
{
Point p = (Point)a;
Rectangle pointRect = new Rectangle(p, small);
g.DrawRectangle(pointPenIn, pointRect);
pictureBox1.Refresh();
textBox1.Text=""+(4 * (double)hitPoints / (double)currentPoints);
if (currentPoints >= maxPoints) //fertig
{
running = false;
nupPointNumber.ReadOnly = false;
btnStart.Text = "Start";
return;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
switch (comboBox1.SelectedIndex)
{
case 0:
sleepTime = (int)waitTime.ultra;
break;
case 1:
sleepTime = (int)waitTime.wif;
break;
case 2:
sleepTime = (int)waitTime.sschnell;
break;
case 3:
sleepTime = (int)waitTime.schnell;
break;
case 4:
sleepTime = (int)waitTime.normal;
break;
case 5:
sleepTime = (int)waitTime.langsam;
break;
case 6:
sleepTime = (int)waitTime.slangsam;
break;
case 7:
sleepTime = (int)waitTime.slowmo;
break;
}
}
}
}
Ergänzung ()
Neuster Code mit Background Workern.
Ich glaube mein Fehler ist einfach das ich den UI Thread zu sehr fordere mit dem Neuzeichnen.
Wo und WIE kann ich noch Sachen aus dem UI Thread auslagern, damit der nicht mehr blockiert?
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
namespace Monte_Carlo_Visualisierung
{
public partial class Form1 : Form
{
List<Point> pointList = new List<Point>();
bool running = false;
Random Rand = new Random(); //Zufallsgenerator
Bitmap picture = new Bitmap(500, 500);
Graphics g;
Pen bigPen = new Pen(Color.Black, 4); //Farbe + Stärke
Pen smallPen = new Pen(Color.Black, 2);
Pen pointPenIn = new Pen(Color.Red, 1);
Pen pointPenOut = new Pen(Color.Blue, 1);
Size small = new Size(1, 1);
int maxPoints = 10; //Wieviele Punkte dürfen höchstens geworfen werden
int currentPoints = 0; //Alle in Auftrag gegebenen Punkte
int drawnPoints = 0; //alle wirklich bereits gezeichneten Punkte
int hitPoints = 0; //Punkte im Kreis
int failPoints = 0; //Punkte außerhalb des Kreises
int sleepTime = 0;
/*
Ultraschnell (0ms)
Wie im Fluge (1ms)
Sehr schnell (50ms)
Schnell (100ms)
Normal (250ms)
Langsam (500ms)
Sehr Langsam (1000ms)
Slow Motion (3 Sekunden)
*/
public Form1()
{
InitializeComponent();
g = Graphics.FromImage(picture);
DrawBasis();
comboBox1.SelectedItem = comboBox1.Items[0];
}
//Box und den Kreis zeichnen, einfärben
private void DrawBasis()
{
picture = new Bitmap(500, 500);
g = Graphics.FromImage(picture);
picture.MakeTransparent();
//Box zeichnen
Rectangle box = new Rectangle(0, 0, 500, 500);
SolidBrush brushWhite = new SolidBrush(Color.Gray);
SolidBrush brushNavy = new SolidBrush(Color.Turquoise);
//Box zeichnen und einfärben
g.DrawRectangle(bigPen, box);
g.FillRectangle(brushWhite, box);
//Kreis zeichnen und einfärben
g.DrawEllipse(smallPen, box);
g.FillEllipse(brushNavy, box);
pictureBox1.Image = picture;
pictureBox1.Refresh();
}
private void tbInterval_KeyPress(object sender, KeyPressEventArgs e)
{
//akzeptiere nur Zahlen (Zeit ist in Millisekunden)
if (!Char.IsDigit(e.KeyChar))
e.Handled = true;
}
enum waitTime { ultra = 0, wif = 1, sschnell = 50, schnell = 100, normal = 250, langsam = 500, slangsam = 1000, slowmo = 3000 };
private void btnStart_Click(object sender, EventArgs e)
{
//keine aktiven Worker = Start Button
if (running == false)
{
btnStart.Text = "Stop";
nupPointNumber.ReadOnly = true;
running = true;
//Zurücksetzen auf 0
DrawBasis();
maxPoints = Int32.Parse(nupPointNumber.Text);
pointList.Clear();
//Zähler auf 0
currentPoints = 0;
drawnPoints = 0;
hitPoints = 0;
failPoints = 0;
//für jeden CPU Core einen BackgroundWorker anlegen (-1 für die UI)
for (int i = 0; i < Environment.ProcessorCount; i++)
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerAsync();
}
}
//aktive Worker = Stop Button
else
{
// DrawBasis();
running = false;
btnStart.Text = "Start";
nupPointNumber.ReadOnly = false;
}
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
while (drawnPoints < maxPoints)
{
if (running == true)
{
Thread.Sleep(sleepTime);
Point p1 = new Point(Rand.Next(500), Rand.Next(500));
Point m = new Point(250, 250); //mittelpunkt
//Entfernung von p1 zu m darf nicht mehr als 250 pixel betragen, sonst außerhalb des Kreises
float d = (float)Math.Sqrt((p1.X - m.X) * (p1.X - m.X) + (p1.Y - m.Y) * (p1.Y - m.Y));
if (d < 250)
hitPoints++; //Abstand kleienr als 250 -> innerhalb des Kreises, Zähler erhöhen
else
failPoints++; //Abstand größer als 250 -> außerhalb des Kreises, Zähler erhöhen
try
{
this.Invoke(new ImageDelegate(drawPoint), p1);
}
catch
{
return;
}
}
else
{
break;
}
}
running = false;
}
public delegate void ImageDelegate(object a);
private void drawPoint(object a)
{
Point p = (Point)a;
Rectangle pointRect = new Rectangle(p, small);
g.DrawRectangle(pointPenIn, pointRect);
drawnPoints++;
if (drawnPoints >= maxPoints) //fertig
{
running = false;
nupPointNumber.ReadOnly = false;
btnStart.Text = "Start";
return;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
switch (comboBox1.SelectedIndex)
{
case 0:
sleepTime = (int)waitTime.ultra;
break;
case 1:
sleepTime = (int)waitTime.wif;
break;
case 2:
sleepTime = (int)waitTime.sschnell;
break;
case 3:
sleepTime = (int)waitTime.schnell;
break;
case 4:
sleepTime = (int)waitTime.normal;
break;
case 5:
sleepTime = (int)waitTime.langsam;
break;
case 6:
sleepTime = (int)waitTime.slangsam;
break;
case 7:
sleepTime = (int)waitTime.slowmo;
break;
}
}
}
}