Einloggen Suche | Aktive Themen
IStamminformationen Object wird nicht befüllt(Multiple Threads) Optionen
Florian Legerer
Geschrieben: Monday, October 17, 2016 10:05:26 AM
Gruppen: Kunde

Beiträge: 1

Hallo,

Herr Julius hat schon eine Reihe von Emails mit ähnlichen Problemen von mir bekommen, um ihn zu entlasten schreib ich jetzt mal ins Forum Smile

Ich habe eine Liste mit FStammInfo Objekten (Class ist wie IStammInfo Class, nur Serializable).

Für jedes dieser Objekte möchte ich IStamminformationen. Da ein sequentieller Aufruf von mehreren tausend IStamminformationen ewig dauert, spalte ich die Arbeit mittels TPL in Threads auf.

Das funktioniert gut für eine kleine Anzahl an Objekten. Bei einer größeren Anzahl bekomme ich jedoch für mehr als die Hälfte keine IStamminformationen zurück (stammInformationen.SymbolNr = 0).

Momentan sammle ich diese Symbolnummern (in concurrentBagEmptyStammInformationen) und probiere es nacher noch einmal (insgesamt 5 Versuche). Jeder weitere Versuch ist wiederum teilweise erfolgreich, so dass sich die Anzahl an "leeren" Objekten verringert - trotzdem:

Warum bekomme ich für mehr als die Hälfte von Abfragen keine Stimminformationen zurück?
Ist der COM Server überlastet? Wenn ja, würde ein Thread.Sleep(200) vor jeder Interface Abfrage helfen?
Oder soll ich IStamminformationen stammInformationen global definieren um nicht jedesmal neu zu instanzieren?

Hier der entsprechende Code:

Code:
public static List<FZertifikat> GetFZertifikateListFromStammInfoList(List<FStammInfo> fStammInfos)
        {
            var concurrentBagOfFZertis = new ConcurrentBag<FZertifikat>();
            var concurrentBagEmptyStammInformationen = new ConcurrentBag<FStammInfo>();
            int cnt = 0;

            Console.WriteLine("Start creating Zertifikate List from StammInfo...");

            while (cnt++ < 5)
            {
                Parallel.ForEach(fStammInfos, (fStammInfo) =>
                {
                    var fZertifikat = FillStamminformationen(fStammInfo);

                    if (fZertifikat != null && fZertifikat.SymbolNr > 0)
                    {
                        concurrentBagOfFZertis.Add(fZertifikat);
                    }
                    else
                    {
                        concurrentBagEmptyStammInformationen.Add(fStammInfo);
                    }
                });

                if (concurrentBagEmptyStammInformationen.Count == 0)
                {
                    break;
                }

                fStammInfos.Clear();
                fStammInfos = concurrentBagEmptyStammInformationen.ToList();
                concurrentBagEmptyStammInformationen = new ConcurrentBag<FStammInfo>();

                Console.WriteLine("NULL or failed Values left after Run: " + fStammInfos.Count);
            }

            Console.WriteLine("Zertifikate List from StammInfo List retrieved!");
            return concurrentBagOfFZertis.ToList();
        }

        private static FZertifikat FillStamminformationen(FStammInfo fStammInfo)
        {
            IStamminformationen stammInformationen = new StamminformationenClass();
            stammInformationen.SymbolNr = fStammInfo.SymbolNr;
            var fZertifikat = ZertifikateManager.GetFZertifikateFromStammInformationen(stammInformationen, fStammInfo);
            stammInformationen = null;
            return fZertifikat;
        }
Thorsten Kitzig
Geschrieben: Tuesday, February 28, 2017 12:50:46 PM
Gruppen: Insider

Beiträge: 22

Tai-Pan RealtimeTai-Pan End-of-Day
Hallo Herr Legerer,

versuchen sie doch mal den Array-Loader.
Code:
ArrayLoader loader = new ArrayLoader();

//Wertpapiere werden über die SymbolNummer eindeutig identifiziert
//diese kann über das Stammdatenfenster in Tai-Pan Realtime oder über eine Titelsuche (mittels der Suchen-Methode des DataBase-Objektes)
//über den COM-Server ermittelt werden ( siehe cmdDatabaseIntraday_Click() )         
int[] symbolNr = new int[5]
                {
                    78303,          //555750.ETR        Dt.Telekom
                    169286,         //710000.ETR        Daimler AG
                    78275,          //519000.ETR        BWM ST
                    78340,          //766403.ETR        VW ST
                    78267           //823212.ETR        Lufthansa
                };

StammdatenCollection stammCol = loader.Stammdaten(symbolNr) as StammdatenCollection;
if( stammCol != null )
{
    Debug.WriteLine(Environment.NewLine);

    //die StammdatenCollection enthält die einzelnen Stammdaten...
    foreach( Stamminformationen stamm in stammCol )
    {
        //...die nun ausgelesen werden können
        Debug.WriteLine("{0}   {1}", stamm.Name, stamm.Symbol, stamm.FullSymbol);
    }
}

Dieses Beispiel habe ich aus dem Zip-File "ArrayLoaderSample.zip" welches sich im Tai-Pan Realtime Programmverzeichnis befindet.

Damit lassen sich auch 5000 oder mehr Stammdaten schnell laden ohne das eine "Paralles" Anweisung nötig ist. Die Paralles-Anweisung startet ja jeweils mehrere Threads die wiederum jeweils eine einzelne Anfrage zur Folge hat. Der Aufruf von ArrayLoader ist nur eine Anfrage die alle Stammdaten hintereinander streamt.

Hierzu gleich eine Anmerkung: .net hat eine kleine Schwachstelle bzgl. der Verwendung von COM-Objekten. Der Aufruf von foreach ruft vom Objekt "stammCol" ein enum-Interface ab, welches foreach dann für die Schleife verwendet. Da nun aber nach dem Abrufen des enum-Interfaces keine weiteren Aufrufe an das Object "stammCol" mehr im Quelltext vorkommen, erkennt das die optimierung des Compilers und setzt den Referenzcounter bereits auf 0. Das kann dazu führen, dass der Garbage Collector von .net das Objekt "stammCol" freigeben will obwohl noch ein foreach läuft. Dieses Problem tritt vor allem bei größeren Listen von Wertpapieren auf. Das lässt sich nur dadurch ändern, dass nach der foreach Schleife noch Zugriffe auf das Objekt "stammCol" existieren, oder der Zugriff auf eine For()-Schleife geändert wird.
Code:
for (int nReadIndex = 1; nReadIndex <= stammCol.Count; nReadIndex++)
{
    Stamminformationen stamm = stammCol[nReadIndex];
    Debug.WriteLine("{0}   {1}", stamm.Name, stamm.Symbol, stamm.FullSymbol);
}
ACHTUNG: Com-Aufzählungen beginnen immer bei 1 als kleinster Index!

Grüße

Thorsten Kitzig
Benutzer die diese Diskussion aktuell lesen
Guest

Powered by Yet Another Forum.net version 1.9.1.8 (NET v4.0) - 3/29/2008
Copyright © 2003-2008 Yet Another Forum.net. All rights reserved.

Durch die Nutzung der Webseite stimmen Sie der Verwendung von Cookies zu. Weitere Informationen zum Datenschutz finden Sie hier