Hallo,
ich bin mittlerweile am Verzweifeln mit meinem Backgroundworker!
In meiner Anwendung lese ich Sensorwerte aus und speichere diese in einer Array List! Damit die Oberfläche in dieser Zeit nicht stehen bleibt geschieht dies in einem Backgroundworker. Leider brauche ich für das Sammeln der Werte in meiner Schleife fast 20sec dafür. Wenn ich es nicht als Backgroundworker ausführe sind es nur noch 5sec. Kann mir vielleicht jemand einen Tip geben warum das sooooooo.... lange dauert?
Vielen Dank für eure Hilfe!
schirmi87
public void StartMeasuring()
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = false;
worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
Double measureValue = 0.0;
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 2; j++)
{
measureValue = Taster.ReadLiveValue(j);
measureValues[j].Add(measureValue);
}
}
};
worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
MessageBox.show("Fertig");
}
};
worker.RunWorkerAsync();
}
So brauche ich nur** 5sec** wenn ich es direkt ausführe, aber die Oberfläche in dieser Zeit eingefroren bleibt.
Double measureValue = 0.0;
for (int i = 0; i < PruefPlan.MeasuringPoints; i++)
{
for (int j = 0; j < probeCont.Count; j++)
{
measureValue = Taster.ReadLiveValue(j);
measureValues[j].Add(measureValue);
}
}
MessageBox.Show("Fertig");
Hallo schirmi87,
komisch.. was genau passiert denn hinter dem Taster.ReadLiveValue bzw. ist das eine Methode von dir?
Gruß
Roland
Alles was ich dir sagen kann ist das ich das Problem mit dem Backgroundworker gut kenne. Bei mir werden dann aus 45 sekunden schnell mal 3 Minuten.
Warum weshalb wieso kann ich leider auch nur vermuten, evtl. die Thread Prio. bzw. das der eigentliche Gui Thread zuviel Aufmerksameit auf sich zieht - keine Ahnung.
Hallo schirmi87,
... in einer Array List!
ArrayList gehört in die Mottenkiste und sollte wie alle untypisierten Collections aus System.Collections nicht mehr benutzt werden. Verwende stattdessen List<T> und alle anderen typisierten Collections aus System.Collections.Generic.
herbivore
Hallo Kollegen,
also das Backgroundworker langsamer ist sollte m. E. nicht sein. Ist mir bis jetzt so auch noch nie aufgefallen. Folgender kleiner Test-Code gibt bei mir gleiche Ergebnisse (mit und ohne Backgroundworker):
BackgroundWorker m_bgWorker;
/// <summary>
/// Testing using Backgroundworker.
/// </summary>
private void OnCmdTest1Click(object sender, RoutedEventArgs e)
{
long time = 0;
m_bgWorker = new BackgroundWorker();
m_bgWorker.DoWork += (x, y) => { time = DoSomething(); };
m_bgWorker.RunWorkerCompleted += (x, y) => MessageBox.Show("Finished in " + time + " milliseconds!");
m_bgWorker.RunWorkerAsync();
}
/// <summary>
/// Testing without Backgroundworker.
/// </summary>
private void OnCmdTest2Click(object sender, RoutedEventArgs e)
{
long time = DoSomething();
MessageBox.Show("Finished in " + time + " milliseconds!");
}
/// <summary>
/// Simulates some work.. ;)
/// </summary>
public long DoSomething()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
//Simulation some work here
for (int loop = 0; loop < Int32.MaxValue; loop++) { }
stopWatch.Stop();
return stopWatch.ElapsedMilliseconds;
}
Beide Test brauchen ungefähr 5,5 Sekunden.
Gruß
Roland
Hallo Sebastian,
genau von sowas gehe ich aus, denn deswegen habe ich oben gefragt, was genau da innerhalb von DoWork gemacht wird. Wenn jedemenge Invokes aufgerufen werden ist es klar, dass der Backgroundworker länger braucht. In diesem Fall kann man sich auf so wenige Invokes wie möglich beschränken, um die Performance zu steigern. Eventuell kann man auch BeginInvoke verwenden, da hier der Worker-Thread nicht wartet, bis die Gui aktualisiert ist, allerdings muss man aufpassen, dass man die Gui nicht zuballert.
Gruß
Roland
Also ich habe es jetzt nochmal ohne extra Gui Ausgabe getestet.
WorkerReportsProgress = false;
Der Effekt bleibt der gleiche, der Backgroundworker braucht bis zu 10x so lange.
Meine Hoffnung das es im ReleaseBuild nicht auftritt hat sich leider auch zerschlagen. Irgendeine Idee woran das liegen könnte?
Du machst doch irgendwo selber invokes, und diese "sind die falle".
Wie sieht denn dein code aus?
Hallo FZelle,
Nein keine Invokes, ich hatte wie gesagt testweise sämtlichen Gui Code entfernt.
Es sieht so als ob z.B. Befehle die das Filesystem betreffen(laden von Dateien)
deutlich langsamer sind, ich arbeite noch dran das zu genauer zu prüfen.
Der Code ist recht umfangreich und hier schlecht zu posten.
Falls du dir das wirklich antun willst.
http://latebindingapi.codeplex.com/SourceControl/list/changesets
Einfach den letzten Stand downloaden.
Wenn ich zb. die Excel TypeLibrary ohne Use Backgroundworker analysiere
dauert das auf meinem Rechner 1:23 mit Backgroundworker dann schon mal
10 Minuten.
Hallo Sebastian.Lange,
... ich arbeite noch dran das zu genauer zu prüfen.
das geht am besten mit einem Profiler, aber das weiß du vermutlich. Ich wollte es nur zur Sicherheit schreiben.
herbivore
@Sebastian.Lange:
Da man das Projekt nicht compilieren kann, kann man auch nicht sehen wo da die Zeit verplempert wird.
Hallo herbivore!
...
das geht am besten mit einem Profiler, aber das weiß du vermutlich. Ich wollte es nur zur Sicherheit schreiben.
Kannst du einen Profiler empfehlen?
Viele Grüße,
Florian
Hallo deerhunter,
Kannst du einen Profiler empfehlen?
es gibt mehrere Threads im Forum, in denen Profiler empfohlen wurden. Bitte benutze die Forensuche.
herbivore
TLI fehlt.
Aber da hast du auch schon dein Problem, COM/ActiveX und Multithreading passen nicht zusammen.
Hallo Sebastian,
ich bin mir nicht ganz sicher, aber eventuell hat es etwas mit dem thread-apartment zu tun. Der Gui-Thread läuft ja i. d. R. als STAThread. Der Hintergrund-Thread vom BackgroundWorker müsste ein MTAThread sein.
Versuche mal selbst einen Thread anzustarten, der mit STAThread markiert ist und messe da die Zeit.
Gruß
Roland
Leider hat das mit dem STA Tread nicht funktioniert.
Ohne Thread 02:03 und mit STA Thread 13:53 *heavy
Mein (recht schnell zusammengezimmerter) STA Thread Code sieht dabei so aus.
public delegate void ThreadProgressHandler();
public delegate void ThreadCompletedEventHandler();
internal class ThreadJob
{
Thread _thread = null;
private System.Windows.Forms.Timer _endTimer;
public event ThreadStart DoWork;
public event ThreadCompletedEventHandler RunWorkerCompleted;
public bool IsAlive
{
get
{
return _thread.IsAlive;
}
}
public void Start()
{
_thread = new Thread(DoWork);
_thread.SetApartmentState(ApartmentState.STA);
_thread.Priority = ThreadPriority.Normal;
_thread.IsBackground = false;
_thread.Start();
_endTimer = new System.Windows.Forms.Timer();
_endTimer.Interval = 100;
_endTimer.Tick += new EventHandler(_endTimer_Tick);
_endTimer.Enabled = true;
}
public void Abort()
{
_thread.Abort();
}
private void _endTimer_Tick(object sender, EventArgs e)
{
if (false == _thread.IsAlive)
{
if (null != RunWorkerCompleted)
RunWorkerCompleted();
_endTimer.Enabled = false;
}
}
}
Komische Sache..
wenn ich jetzt einmal laut denke.. Wies aussieht, will dieses Excel-Interop zeugs irgendwas mit dem aktuellen Gui-Thread machen. Theoretisch könnte man mal per Application.AddMessageFilter(...) schauen, ob während der Zeit, in der auf Excel-Interop zugegriffen wird, irgendwelche Nachrichten ankommen. Falls dem so wäre, könnte man einfach in dem Worker-Thread eine neue Applications-Nachrichtenschleife starten, per Application.Run oder sowas.
Gruß
Roland