UI Thread se blochează folosind BlockingCollection rapid?

Sunt pe cale să scriu o aplicație care primește date streaming de pe portul TCP, făcând niște calcule în timp real pe ele. Toate bune până acum, dar interfața cu utilizatorul și bara de progres a marcajului se blochează (pentru perioade neregulate, scurte) atunci când firul producătorului începe să facă niște ambalaje pe bucăți de date (a se vedea codul).

        void Produce()
    {
        try
        {
            while (true)
            {
                foreach (Chunk _chunk in bcPort)
                {
                    if (_ThreadCanceler.IsCancellationRequested) break;
                    Chunk chunk = bcPort.Take();
                    chunk.TimeTracker = new Stopwatch();  
                    chunk.SegmentId = iSegmentId;
                    if (chunk.Channel + 1 == iChannels) iSegmentId++;//last channel, raise segment id.                     
                    iPrevChannel = chunk.Channel;
        //        _ProcessAndJoin.EnqueueTask(chunk, _ThreadCanceler);                       
                    iChunksProduced++;
                    _LogWriter.WriteMessage("Task " + Task.CurrentId.ToString() + "(producer): ADDED_ Chunk[" + chunk.Channel + ":" + chunk.Vals.Count.ToString() + ":" + chunk.SegmentId + "] [" + iChunksProduced + "]. " + bcPort.Count + " for takeaway. Thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                }
                if (_ThreadCanceler.IsCancellationRequested) break;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("ForkAndCrate.cs: Produce(): " + ex.ToString());
        }
    }

Am făcut o mulțime de teste și am aflat că accesul la bcPort BlockingCollection pare să fie problema. bcPort primește constant bucăți de la un alt fir de date-adder care se presupune că nu influențează firul ui. Deci nu înțeleg următoarele:

1.) De ce se blochează interfața grafică atunci când folosesc fire diferite pentru adăugarea și ambalarea bucatile?

2.) De ce se întâmplă acest lucru când folosesc un BC pentru stocarea datelor? Nu sunt aceste colecții în condiții de siguranță pentru acest scop?

Apropo: Windows 7 ResourceManager arata 100% folosirea CPU-ului in timpul streaming-ului, bucatile contin aproximativ 2000 de valori flotate fiecare, 4 sau 5 dintre acestea se grabesc in secunda. De asemenea, am dezactivat loggerul, dar nu am nici un efect. Firele de consum și de evaluare sunt dezactivate.

În afară de firul ui, există doar un fir numit "ReceiveAndSave", care face bucăți din valori de intrare float (a se vedea codul, metoda "Adăugați"). firul "Producător" face mai multe împachetări și încalcă bucățile pentru consumator (dezactivat).

   public void Add(short iChannel, float fValue)
    {
        try
        {
            _Benchmark.UpdateRec(); //one value received, update benchmark:
            if (!cdBasin[iChannel].Enqueue(fValue))
            {
                Chunk chunk = new Chunk();
                chunk.Vals = cdBasin[iChannel].ToListDeep;
                chunk.Channel = iChannel;
                bcPort.Add(chunk);
                cdBasin.AddOrUpdate(iChannel, new BoundedQueue(iSegmentSizePerChannel), (key, oldValue) => new BoundedQueue(iSegmentSizePerChannel));
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString(), "Stop", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }
    }

Producătorul a început cu 'myThreads [0] = Thread nou (Produce); myThreads [0] .Name = "Produce"; myThreads [0] .Start ();“

0
metoda de adăugare pare a fi un pic ciudat, dar bucățile trebuie să aibă exact 500 vale fiecare și trebuie să rămână conectate la canalul lor, ceea ce nu este ușor de asigurat de atâtea date care se grăbesc. în plus, din motive de performanță, nu vreau să utilizeze eliminarea din dicționar sau de la bc, deoarece este foarte costisitoare, așa că sunt în curs de actualizare în loc de eliminare și adăugare. dar metoda de adăugare nu este problema, rulează foarte netedă și rapidă, atâta timp cât producătorul nu accesează BlockingCollection "bcPort".
adăugat autor Rome, sursa
Nu este clar unde se difuzează codul pe care l-ai postat sau ce fire ați avut de fapt ... vă rog să vă clarificați situația.
adăugat autor Jon Skeet, sursa

1 răspunsuri

Nu se blochează, dați-i prea mult de făcut. Ceea ce îl face să nu mai aibă grijă de sarcinile sale cu prioritate scăzută, răspunzând la notificările de intrare și vopsea. Ceea ce face într-adevăr că arata </​​em> ca este blocat, utilizatorul dvs. va gândi cu siguranță.

Cheia este aceea de a actualiza interfața utilizator doar la o rată care are sens în ochiul uman. Care nu poate percepe nimic altceva decât o blur de peste 25 actualizări pe secundă. Dacă îl împingeți la o mie de actualizări pe secundă, veți obține comportamentul pe care îl descrieți. Prin urmare, colectați rezultatele și nu invoca/actualizați până când nu a mai expirat suficient timp. Și, în general, compactați informațiile pe care le afișați în bucăți consumabile pentru a oferi utilizatorului feedback semnificativ, o listă care afișează sute de articole noi pe secundă nu este utilă nimănui.

0
adăugat
mulțumesc. fișierul log este menit doar ca un ajutor pentru mine, pentru a vedea dacă lucrurile se întâmplă în mod corect. pentru feedback-ul utilizatorilor am un evaluator care invocă un punct de referință al bucăților prelucrate în gui doar în fiecare secundă. așa că problema mea este mai mult o problemă cosmetică și bara de progres a marcajului nu pare a fi corectă pentru a afișa procesarea continuă. există o altă modalitate frumoasă de a afișa progresul constant al utilizatorului într-un astfel de caz intensiv de calcul (pe lângă criteriul meu de referință)?
adăugat autor Rome, sursa
Orice este posibil, un simplu contor va face. Fragmentul dvs. este prea opac pentru a da o recomandare specifică.
adăugat autor Hans Passant, sursa