Laden...

Forenbeiträge von andski Ingesamt 9 Beiträge

10.07.2013 - 08:35 Uhr

Hallo und Danke an eure Vorschläge.

@mogel: Es läuft momentan so, wie Du es vermutet hast: Datei öffnen, schreiben, schließen.
Die Variante mit dem Prozess klingt noch einen Tick sicherer. Ich werde es mal so machen.

Gruß
andski

05.07.2013 - 08:35 Uhr

Hallo,

an so eine Lösung habe ich noch gar nicht gedacht.
Aber gibt es auch eine Möglichkeit, den Logger als Klasse direkt im Program zu implementieren, sodass bei einer sehr großen Nachrichtenflut möglichst jede Nachricht sofort in die Datei geschrieben wird? Die Probleme hierbei sind also einmal dass sich schneller neue Nachrichten anhäufen, als geschrieben werden können (es sei denn man schreibt eine Menge Nachrichten mit einem Mal, was aber wieder zu Datenverlust führen kann).

Gruß
andski

04.07.2013 - 17:22 Uhr

Hallo,

ich will aus Interesse einen Logger implementieren. Folgendes muss gehen:* Nachrichten in eine Datei schreiben.

  • Möglichen Datenverlust minimieren. Das heisst, im Falle eines Absturzes sollen nicht die letzten 200 Meldungen verloren gehen. Der Logger muss also fast jede Nachricht sofort in die Datei schreiben.
  • GUI darf in ihrer Performance nicht beeinflusst werden.

Mein bisheriger Ansatz besteht darin, dass die Logger-Klasse einen Writer-Thread startet, der 10 mal pro sekunde alle Nachrichten in der Queue in die Datei schreibt. Probehalber habe ich das mit einer Schleife mit 100.000 Iterationen getestet. Jeder Durchlauf ruft einmal die log()-Funktion auf. Im Hintergrund läuft der Writer-Thread und schreibt die Datei. Das Ganze dauert etwa 0.5 sekunden.

Offenkundiges Problem: In der Zeit, in der der Writer-Thread schläft wird die Queue gefüllt. Stürzt das Programm jetzt ab, sind die letzten x-Tausend Meldungen weg. Nicht Gut.

Um dies zu "lösen" müsste also jede Nachricht sofort in die Datei geschrieben werden. Das ging bisher jedoch nur auf Kosten der Performance. 100.000 Einträge dauerten somit ca. 15 Sekunden.

Ich habe mir mal eine kleine Test-Applikation gebaut, die log4net verwendet. Für 100.000 Logs brauchte ich so ebenfalls 0.5 Sekunden. Allerdings weiss ich nicht wie das dort implementiert wurde.

Mir ist bewusst, dass 100.000 Nachrichten in so extrem kurzer Zeit in den meisten Fällen kaum geloggt werden müssen. Jedoch interessiert es mich, wie man an diese Sache heran gehen kann, um bei sehr guter Performance möglichst jede Meldung sofort zu loggen.

Bitte deshalb um Rat und bin dankbar für Hinweise.

Gruß
Andski

12.06.2013 - 09:09 Uhr

Um meine Frage mal selbst zu beantworten:

Wonach ich gesucht habe, wird hier beschrieben. Dort wird eine eigene dictionary-Klasse erstellt, die von INotifyPropertyChanged abgeleitet wird und beim Hinzufügen, Löschen oder Ändern von Einträgen ein PropertyChangedEvent auslöst.

Man kann dann die Zeilendaten als normale Einträge zu diesem Dictionary hinzufügen und packt das gefüllt Dictionary dann in eine ObservableCollection, die an ein DataGrid o.ä. gebunden ist.

Zur Laufzeit lassen sich somit beliebig hinzugefügte Spalten mit Daten füllen.

31.05.2013 - 12:35 Uhr

Hallo,

ich habe eine ListView mit GridView. Diese hat schon 10 Spalten. Nun möchte zur Laufzeit eine neue (11.) Spalte zur GridView hinzufügen. Wenn ich anschließend eine neue Zeile einfüge, soll natürlich auch die Zelle der neuen Spalte belegt werden können.

Soweit ich das verstanden habe muss ich der ListView eine ObservableCollection (zumindest etwas, was INotifyCollectionChanged implementiert) als ItemSource angeben. Zur ObservableCollection können dann Items hinzugefügt werden, bspw. mittels eines anonymen Objekts:

observableCollection.Add(new {Name = "A", Val = "B"});

Das ganze lässt sich auch über eine Klasse, die Properties definiert, bewerkstelligen.

Der Knackpunkt ist aber der gleiche: zur Laufzeit lassen sich weder dem anonymen Objekt, nach zur Klasse dynamisch Eigenschaften hinzufügen.

Gibt es einen Weg, sowas zu machen?

30.05.2013 - 08:43 Uhr

Hallo,

Was hindert dich also, den Wert in den richtigen Typ zu konvertieren und in einer Variable dieses Typs zu speichern?

Mich hindert, dass ich nicht vorraussetzen kann, dass die Werte in der Datei auch die Vorraussetzungen erfüllen in die gewünschten Typen geparst werden zu können.
Beispiel: VAR=10.0
Ich will einen double haben, den ich so auch bekommen würde.
Aber VAR=10.xy würde ein String werden. Und dann knallt es zur Laufzeit dort, wo ich einen double verwenden will.

Unterm Strich lässt sich das Problem so zusammen fassen: Ich weiss nie, ob meine File-Reader-Klasse die Werte in die gewünschten Typen parsen kann. Das heisst, dass ich irgendwo prüfen muss, ob es sich nun tatsächlich um einen int-Wert handelt.

Meine vorgeschlagene unkonventionelle Lösung würde IMMER für jeden Typ eine Variable bereithalten, die wenigstens mit dem default-wert belegt ist. will ich dann auf den Wert einer bestimmten Variablen zugreifen sähe das irgendwie so aus:

double dbl_val = my_hash["VAR"].dblVal;

Wobei wie gesagt der Wert für den Key "VAL" im Hash eine Instanz von dem hier ist:

public struct values
{
    int intVal;
    double dblVal;
    string strVal;
}

(Nur ums mal zu verdeutlichen. Das lässt sich noch ausbauen.) Wobei halt nur eine der drei Variablen den tatsächlichen Wert (eben je nach erkanntem Typ) enthält und die anderen beiden ihre default-Werte haben.

Gruß
andski

29.05.2013 - 13:36 Uhr

Hallo,

danke für deine Antwort. So habe ich es jetzt auch umgesetzt.

An dieser Stelle möchte das ganze etwas ausdehnen. Und zwar nutze ich diese Methode in einem größeren Kontext: In einer Textdatei habe ich Key-Value Paare stehen. Die Werte können Int32, Double, oder String sein. Um den Typ zu erkennen benutze ich reguläre Ausdrücke. Wird Int32 oder double erkannt, verwende ich die hier besprochene Methode, um den Wert in einen Integer oder eben Double zu konvertieren. Die Key-Value Paare werden dann in einer Hashtable gespeichert.
Hier habe ich die Möglichkeit die konvertierten Werte direkt zu speichern, oder mir einen generischen struct zu bauen, für jeden Wert eine Instanz dieses structs zu erzeugen und diesen in der Hashtable zu speichern. Da eine Hashtable alles als object speichert, bedeutet erstere Variante, dass ich ständig casten muss, wenn ich die Werte verwenden will. Bei letzterem würde der Cast wegfallen, was schon mal schön bequem wäre.

Nun zum Problem:
Bei der Verwendung der konvertierten Werte soll möglichst kein weiterer Aufwand entstehen. Das heisst, dass ich gerne sicherstellen möchte, das ein Wert einen bestimmten Typ hat. Dies ist insofern notwendig, da die Typerkennung automatisch abläuft und es auch einmal zu einer Fehlerkennung kommen kann. Bspw hat jemand an der Textdatei rumgespielt und einen Buchstaben an einen Wert, der eigentlich ein int ist, angehängt. Der Wert würde somit als String und nicht als int erkannt werden. Um diese Fehlerquellen auszuschließen müsste ich im Code ständig prüfen ob es sich tatsächlich um einen int handelt.

Ich habe für dieses Problem eine etwas unkonventionelle Lösung. Statt eines generischen structs erzeuge ich einen struct mit einer string-Variablen, einer int-Variablen und einer double-Variablen. Da ich weiss welche Typen meine Werte annehmen können, kann ich das tun. Der konvertierte Wert wird dann in der entsprechenden Variablen gespeichert. Verwende ich nun den Wert, müsste ich mir lediglich die richtige Variable aussuchen.

Wenn ich keinen Denkfehler drin habe, sollte das mein Problem lösen und einigermassen sicherstellen, dass ich nicht versuche einen string-Wert nicht in einer int-Variablen zu speichern.

Für alle, die verstanden haben, worauf ich hinaus will: Gibt es dafür eine bessere Lösung? =)

Gruss
andski

17.05.2013 - 09:24 Uhr

Hallo und danke für die Antwort.
Deine Variante hat, wie mir auffiel, vor allem einen Vorteil:
Steckt man (T)Convert.ChangeType(...) in einen try-catch-Block, kann man bei erfolgloser Konvertierung zumindest den default-Wert des Typs T zurückgeben. Somit ist im weiteren Programmablauf sichergestellt, dass auch wirklich der entsprechende erwartete Typ vorliegt.

Bei meiner Variante wird bei missglückter Konvertierung der String so zurückgegeben, wie er der Methode übergeben wurde. Bei der Verwendung eines erwarteten double Wertes würde der entsprechende Cast fehlschlagen. Sowas müsste dann ständig abgefangen werden.

Die Methode sieht nun so aus:


public T GetValueAs<T>(string key)
{
    T ret;
    try
    {
        ret = (T)Convert.ChangeType(key, typeof(T), CultureInfo.InvariantCulture);
    }
    catch (Exception e)
    {
        ret = default(T);
    }
    return ret;
}

16.05.2013 - 18:47 Uhr

Hallo,

ich habe ein kleines Projekt in welchem ich in einer Hashtable Werte ablege. Diese Werte werden aus einer textbasierten ini-Datei ausgelesen und können vom Typ int, double oder string sein. An anderen Stellen im Programm wird dann mit diesen Werten gearbeitet. An diesen Stellen möchte ich keine Typkonvertierung machen müssen. Mein bisheriges Vorgehen sieht irgendwie so aus:


public object convertTo(string toConvert)
{
    double dVal;
    if (double.TryParse(toConvert, out dVal))
        return dVal;

    return toConvert;
}

Letztlich bekomme ich an den Stellen, an denen ich mit den bereits konvertierten Werten arbeiten will also ein object mit richtigem Typ. Nun ist nur noch ein Cast notwendig:


double d = (double)convertTo("1.0");

Meine Frage: Gibt es eine bessere Möglichkeit, Werte aus einer ini-Datei in die vermeintlichen Typen zu konvertieren? Vielleicht so, dass der Cast zum schluss auch noch wegfällt?

Gruß und Dank