Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Methode in Backgroundworker ausgeführt braucht viermal solange
schirmi87
myCSharp.de - Member



Dabei seit:
Beiträge: 13
Herkunft: Thüringen

Themenstarter:

Methode in Backgroundworker ausgeführt braucht viermal solange

beantworten | zitieren | melden

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");
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 392

beantworten | zitieren | melden

Hallo schirmi87,

komisch.. was genau passiert denn hinter dem Taster.ReadLiveValue bzw. ist das eine Methode von dir?

Gruß
Roland
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo schirmi87,
Zitat
... 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
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 392

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

Hallo Blacal,

Ich vermute weil du nicht auf Gui Elemente zugreifst.
ich schätze nämlich die Verzögerungen kommen daher.
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 392

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10083

beantworten | zitieren | melden

[FAQ] Warum blockiert mein GUI? Abschnitt "Die Falle".
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

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?
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10083

beantworten | zitieren | melden

Du machst doch irgendwo selber invokes, und diese "sind die falle".

Wie sieht denn dein code aus?
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Sebastian.Lange,
Zitat
... 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
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10083

beantworten | zitieren | melden

@Sebastian.Lange:
Da man das Projekt nicht compilieren kann, kann man auch nicht sehen wo da die Zeit verplempert wird.
private Nachricht | Beiträge des Benutzers
deerhunter
myCSharp.de - Member



Dabei seit:
Beiträge: 92

beantworten | zitieren | melden

Hallo herbivore!
Zitat von 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
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo deerhunter,
Zitat
Kannst du einen Profiler empfehlen?
es gibt mehrere Threads im Forum, in denen Profiler empfohlen wurden. Bitte benutze die Forensuche.

herbivore
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

[OffTopic]
Hallo FZelle
Also ich habs gerade getestet und kanns prima kompilieren.
Was ist dennn deine Fehlermeldung? Ich vermute mal .NET 3.5 fehlt
oder aber wahrscheinlicher die TlbInf32.dll ActiveX Dll von MS(Api zum auslesen von TypeLibraryInfos) fehlt auf dem System.
[/OffTopic]
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10083

beantworten | zitieren | melden

TLI fehlt.

Aber da hast du auch schon dein Problem, COM/ActiveX und Multithreading passen nicht zusammen.
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

Ja den leisen Verdacht hatte ich auch schon.
Der macht für die Komponente nochmal einen Thread auf und
es kommt es dann zu Wartezeiten so wie ich das jetzt getrackt habe.
Ob es bei schirmi87 so ähnlich ist wäre noch ganz interessant zu wissen.
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 392

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

Geniale Idee. Das mache ich gleich mal.
Ich werde berichten.
private Nachricht | Beiträge des Benutzers
user8744
myCSharp.de - Member



Dabei seit:
Beiträge: 1201

beantworten | zitieren | melden

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;
            }
        }
    }
private Nachricht | Beiträge des Benutzers
Blacal
myCSharp.de - Member



Dabei seit:
Beiträge: 392

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers