Laden...
Avatar #avatar-2894.jpg
gfoidl myCSharp.de - Team
Entwickler in der Gasmotorenbranche (nicht nur Software) Waidring Dabei seit 07.06.2009 6.911 Beiträge
Benutzerbeschreibung
FIS-Speedski (S-DH) world champion 2015 3x FIS-Speedski (S-DH) overall worldcup winner, 2008/09, 2009/10, 2012/13 5x Subaru Velocity Challenge winner, 2009, 2010, 2013, 2014, 2015 7x PopKL Verbier winner, 2009 2x, 2010 2x, 2011 2x, 2013 1x 27 victories in 69 international Speedski-races v_max = 208,333 km/h http://de.wikipedia.org/wiki/Günther_Foidl

Forenbeiträge von gfoidl Ingesamt 6.911 Beiträge

19.04.2021 - 10:51 Uhr

Hallo Sebrahi,

eine direkte Unterstützung für dein Vorhaben gibt es in .NET nicht*.
Das "Stack walking" ist aber ein Runtime-Feature, das intern oft verwendet wird. Nicht nur bei Fehlern, sondern v.a. während einer Garbage Collection um "Roots" in Form von lokalen Variablen (die auf dem Stack liegen) zu finden.

Wenn du nun die Stack-Information eines anderen Threads (wirklich) während der Programmausführung benötigst, so würde ich das via Debugger-/Profiler-APIs machen da es dort Zugriff auf die Stacks gibt. Aber recht trivial ist das nicht.

Sollte der Code im Thread unter deiner Kontrolle sein, so kannst du dort ja via Event, Callback etc. den StackTrace generieren lassen mittels


StackTrace stackTrace = new(fNeedFileInfo: true);   // vom jeweils aktuellen Thread
Console.WriteLine(stackTrace);

Als Textrepräsentation gibt es auch Environment.StackTrace vllt. reicht dir diese Info schon aus? Wenn die Debug-Symbole (*.pdb) vorhanden sind, so werden auch die Zeilennummern angezeigt.
Übrigens gibt es dafür für .NET Core eine nette neue Projekteinstellung um die Debug-Symbole direkt in die Assembly einzubetten, so dass diese immer vorhanden sein und kein Symbol-Server benötigt wird:


<PropertyGroup>
    <DebugType>embedded</DebugType>
</PropertyGroup>

Gehts hingegen eher um "post mortem" Analysen, so können Heapdumps mit Debuggern (bzw. Erweiterungen) wie SOS diese Information liefern.

* früher gab es noch die Überladung new StackTrace(thread, ...)

mfG Gü

13.04.2021 - 12:32 Uhr

Hallo Speedys_Work,

[FAQ] Kommunikation von 2 Forms kann hier analog angewandt werden.

mfG Gü

13.04.2021 - 12:12 Uhr

Hallo M.Lach ,

ja.

mfG Gü

13.04.2021 - 10:53 Uhr

Hallo M.Lach ,

nur in der Taskliste (Taskmanager)

Meinst du jenen von Windows?
Das wäre somit ein Prozess der gestartet werden muss. Angezeigt wird dort der Prozessname (von z.B. der exe).

  
Task t = Task.Run(new Action(taskname2));  
  

Das ist ein Task-Objekt.
Dem kann kein Name gegeben werden. Einem Thead kannst du benennen, damit z.B. in der Thread-Übersicht das erkenntlich ist.

Und wie "kille" ich dann diesen wieder?

Entweder lebt der Prozess od. Task von alleine ab, wenn die Aktion, die ausgeführt werden soll, fertig ist od. der Prozess wird geKillt, der Task kann abgebrochen werden mittels Task cancellation.

Was hast du wirklich vor?

mfG Gü

13.04.2021 - 09:31 Uhr

Hallo DeSchneller,

das switch kannst du dir -- zumindest wie es da steht -- sparen, da keine Fälle unterschieden werden (nur der default-Fall ist da).
Fürs switch schau dir auch Using pattern matching switch statements an.

Wie kann ich das verhindern?

Es gibt auch Fehler die nicht behandelbar sind und den Prozess zwangsweise beenden. Z.B. StackOverflowException, OutOfMemoryException udgl. Siehe dazu auch AppDomain.UnhandledException.

Um welchen Tech-Stack handelt es sich: WinForms, WPF, ...?

Für die MessageBox interessant als Lektüre: Nenne deinen Fall, wo du denkst, ohne modalen Dialog geht es nicht, und ich nenne eine Alternative

mfG Gü

08.04.2021 - 15:21 Uhr

Hallo Sebrahi,

Ergänzung / Hinweis:

Parallel.Invoke auf den Abschluss der Operationen wartet.

Und zwar derart dass der aufrufende Thread (z.B. der Main-Thread) blockiert od. für eine Operation der auszuführenden verwendet wird.
Daher ist auf [FAQ] Warum blockiert mein GUI? zu achten.

Würde der Code wie folgt geschrieben sein


public static async Task Start_myMethod1_asyncron()
{
    await Task.Run(() => {
        myMethod1();
    });
}
public static async Task Start_myMethod2_asyncron()
{
    await Task.Run(() => {
        myMethod2();
    });
}

public static async Task Main(string[] args)
{

    await Task.WhenAll(Start_myMethod1_asyncron(), Start_myMethod2_asyncron());

    //difference?

    Parallel.Invoke(myMethod1, myMethod2);

}

so wird zwar per Task.WhenAll auf das Ende der Ausführungen asynchron gewartet (await), aber während dieser Zeit ist der aufrufende Thread (hier: Main-Thread) "frei" und könnte andere Aufgaben erledigten.
Beim Parallel.Invoke ist das wie erwähnt nicht möglich.

Das soll jetzt nicht heißen dass Parallel.Invoke eher schlecht ist, sondern je nach konkreter Aufgabe kann es sogar sehr nützlich sein.

Wenn du einfach stumpf Methoden aufrufen willst, die auch keinen Rückgabewert/Parameter haben, kannst du das mit Parallel.Invoke machen.

Parallel Linq (PLinq) ist eine weitere Option die ganz passend sein kann.

mfG Gü

06.04.2021 - 20:00 Uhr

Hallo Borbes,

kannst du bitte genauer schreiben was du erreichen willst?
Hab die Frage jetzt ein paar mal gelesen, so wirklich schlau werde ich daraus nicht.

Können die Zahlen in den Listen beliebig angeordnet sein?
Streng genommen bei einer Liste ja nicht, aber meinst du Menge? Dann wären alle Permutation von {1, 2, 3} gleichwertig zu betrachten.

Die Schnittmenge an sich ist ja exakt definiert, aber was verstehst du unter "Schnittmenge" bzw. was soll herauskommen? Beim gezeigten Beispiel dass die 5. mit den anderen ähnlich ist od. dass auch 5 in der Schnittmenge ist?

Gehts um einen Ähnlichkeitsvergleich von gegeben Listen?
"Ähnlichkeitsmaße" gibt es ja etliche und je nach Kontext besser geeignet. Noch hab ich aber keine Ahnung worum es wirklich geht.

Der Ansatz von dannoe ist grundsätzlich vernüftig, nur passt dieser zur Aufgabe?

mfG Gü

03.04.2021 - 14:48 Uhr

Hallo Wilfried,

ist eine schöne Lösung!
Nur wenn in die Zukunft (z.B. 2030) gegangen werden soll, so klappt das nicht, da 1930 herauskommen würde.

Daher sollte der Hinweis von Stefan.Haegele unbedingt berücksichtigt werden.

mfG Gü

02.04.2021 - 10:08 Uhr

Hallo T-Virus,

Für das jahr Problem kannst du ja einfach prüfen ob das Jahr kleiner als 1000 ist.
Wenn ja, dann kannst du einfach + 2000 drauf rechnen und hast das entsprechende Jahr.

Kommt darauf an welches Regelwark gelten soll. Ist 50 2050 od. 1950? Je nachdem sollte ein präzisere Unterscheidung (siehe oben) durchgeführt werden.

mfG Gü

02.04.2021 - 09:16 Uhr

Hallo specialist,

schau mal:


using System;

#nullable enable

while (true)
{
    Console.Write("Bitte gib diesen Monat in Zahl ein: ");
    string? monthInput = Console.ReadLine();

    if (!int.TryParse(monthInput, out int month) || (month < 1 || month > 12))
    {
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine("Ungültiger Wert für einen Monat eingegeben. Erlaubt sind Zahlen 1 bis 12.");
        Console.ResetColor();
        continue;   // Schleife wieder von vorne beginnen
    }

    Console.Write("Bitte gib das Jahr ein: ");
    string? yearInput = Console.ReadLine();

    if (!int.TryParse(yearInput, out int year))
    {
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine(@"Ungültiger Wert für ein Jahr eingegeben. Erlaubt sind Zahlenwerte, wobei eine zwei Ziffern Eingabe
wie folgt behandelt wird:
jj <  50 -> 20jj
jj >= 50 -> 19jj");
        Console.ResetColor();
        continue;   // Schleife wieder von vorne beginnen
    }

    year += year switch
    {
        < 50 => 2000,
        >= 50 and < 100 => 1900,
        _ => 0
    };

    DateTime dateTime = new DateTime(year, month, 1);

    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine($"Wir haben {dateTime:MMMM yyyy}");
    Console.ResetColor();
}

Davon ausgehend kannst du es beliebit erweitern bzw. das dir Unbekannte nachlesen (in der Doku). Wenn du dann irgendwo hängst, so frag einfach nach.

mfG Gü

26.03.2021 - 09:27 Uhr

Hallo Pardasus,

einen Windows Dienst

Läuft dieser auf .NET Full od. .NET Core?
Ich würde Letzteres bevorzugen, einfach da es mehr Möglichkeiten gibt.

Seite bauen die Informationen darüber anzeigt, was der Dienst den gerade so treibt.

Je nachdem welche Informationen und in welchem Intervall gibt es verschiedene Varianten in Ergänzung zu Abts Beitrag.
Die hier angeführten können als "Push-Modell" betrachtet werden im Gegensatz zu den bisher genannten "Pull-Modellen".

  • Der Windows-Service ist zugleich ein SignalR-Server, der "Notifications" aussendet und diese werden von der Monitoring-Seite abonniert.
  • Der Windows-Service hat eine EventSource und schreibt in diese die Log-Events, die Monitoring-Seite ist eine Senke dieser Events in Form eines EventListeners

Letztere Variante bietet durch diese Infrastruktur (ist einfacher als es ausschaut) auch die Möglichkeiten mit Diagnose-Werkzeugen ala dotnet-trace, Visual Studio, etc. diese Ereignisse zu analysieren. Od. durch einen speziellen EventListenere auch Alarme zu erzeugen falls eine Metrik eine bestimmten Grenzwert übersteigt / unterschreitet.

Kannst du ein bischen konkreter werden welche Infos angezeigt werden sollen? Damit die Möglichkeiten besser bewertet werden können.
Und auch ob Windows-Service und die Monitoring-Seite im selben Netz / Rechner sind spielt eine gewisse Rolle (Sicherheit).

mfG Gü

19.03.2021 - 13:44 Uhr

Hallo jkrt,

ich lese die Softwareversion des Gerätes und muss dann abhängig von dieser die Daten empfangen und verarbeiten.

um ein paar Entwurfsmuster die da angewandt werden können zu nennen und um dir ein schönes Wochenende zu bereiten 😉* Strategie

Damit kannst du die Unterscheidung durchführen und dann mit der konkreten Instanz die Daten lesen / halten.

mfG Gü

15.03.2021 - 10:30 Uhr

Hallo Kriz,

genau.

Statt simplen String-Verkettungen würde ich aber einen QueryStringBuilder erstellen.
Zuerst die einzelnen Filter in einer Liste speichern und dann daraus am Ende das SQL Statement erzeugt, da so auch einfach parametrisierbar ist.
So kannst du problemen mit den and-"Verknüpfungen" von vornhinein aus dem Weg gehen.

Klar?

mfG Gü

15.03.2021 - 10:01 Uhr

Hallo Kriz,

greifst du mit dem SqlClient auf die DB zu od. wird ein O/R-Mapper ala EF Core, etc. verwendet?

Beim SqlClient kann das Statement (der SQL-String) manuell zusammengestöpselt werden. Achte dabei aber auf [Artikelserie] SQL: Parameter von Befehlen (das hat auch den Vorteil dass im SQL Server der Query-Plan gecached werden kann und so eine bessere Leistung vorhanden ist).

mfG Gü

14.03.2021 - 16:00 Uhr

Hallo vnvjan,

das eigentliche Problem hab ich zu wenig verfolgt, aber bei


[DllImport(@"Master.dll", EntryPoint = "?Init@@YGXPAUHWND__@@0@Z", CallingConvention = CallingConvention.StdCall, SetLastError = true)]

"muss" ich darauf hinweise, dass dieses Vorgehen sehr fragil ist, da durch das Name mangling der EntryPoint bei jeder Version von Master.dll anders sein kann.

Der korrekte Weg wäre hier einen C-Wrapper (zumindest einen extern "C" Export) für die C++ Bibliothek zu erstellen und dann diesen Namen im EntryPoint zu verwenden.
Sonst gibt es später einmal ein Problem und dessen Ursachenforschung mag schwierig sein, da an dies eher nicht gedacht wird (zumindest nicht sofort).

mfG Gü

14.03.2021 - 13:15 Uhr

Hallo zusammen,

endlich finde ich auch die Zeit um ein paar Worte dazu schreiben zu können.

Als ich mich aktiv an der Entwicklung beteiligte war das Projekt schon sehr fortgeschrittenn und dementsprechend auch groß. Das Zurechtfinden innerhalb des Projekts war jedoch wider meines Erwartens relativ einfach, da Abt in Bezug auf Archtitektur, Muster, etc. großen Wert legt(e) und daher so gut wie alles klar und sauber strukturiert war / ist.

Die Zusammenarbeit an diesem Projekt, die ja nach wievor voranschreitet, hat mir einfach Spass und Freude bereitet. Da ich beruflich nur On Premises unterwegs bin, konnte ich für mich neue Möglichkeiten erkunden und erforschen und dabei auf Abts Wissen und Unterstützung zurückgreifen. Danke Ben!

Wie bereits erwähnt wurde, ging jede Änderung via Pull Requests (PRs). Dabei hatten wir etliche konstruktive Diskussionen wie und ob wir etwas noch besser machen könnten. Manchmal wurden bestimmten Ideen zeitlich nach hinten verschoben, damit ein Feature erstmal produktiv werden kann und die Verbesserungen später durchgeführt werden können. Das ein od. andere mal mussten wir uns auch gegenseitig vor der "over engineering"-Falle bremsen 😉 und in anderen Punkten waren wir wohl beide ziemlich gleich stur 🙂 (haben aber immer eine vernüftige Lösung gefunden).

Interessant und spanned ist der Punkt an dem ein Projekt "live" geht immer, hier war es für mich aber besonders interessant, da im "Versuchs-Forum" die Last gering war und dort alle unserer Ziele / Features funktionierten. Im "Live-Forum" mit vielen Benutzer und gleichzeitigen Zugriffen tauchten dann ein paar latente Bugs auf, die meisten ließen sich auf Race-Bedingungen in Zusammenhang mit dem ThreadPool zurückführen, da dieser nun wesentlich mehr Task zu verarbeiten hat als im Versuchs-Forum (so z.B. das Versenden der Emails). (Anmerkung: dies Bugs sind alle behoben).

Es wurde bereits erwähnt, dass wir überlegen bestimmte Teile vom Foren-Code zu veröffentlichen und ein paar Artikel über unsere Erkenntnisse (siehe vorhin) und Muster sowie Tipps und Tricks die wir angewandt haben zu erstellen.
Aber da wir all dies in unserer Freizeit machen, können wir keine verbindliche Zusage zu Terminen machen. Wenns etwas zu veröffentlichen gibt, so werden ihr das schon mitbekommen 🙂

In diesem Sinne wünsche ich euch viel Spass am neuen Forum!

mfG Gü

26.02.2021 - 16:21 Uhr

Hallo,

ohne genaueres von deiner Anwendung zu wissen: ClickOnce wird für .NET 5 unterstützt. Das wäre eine einfache Option.

mfG Gü

25.02.2021 - 09:33 Uhr

Hallo degri2006,

Ich würde nur die Exceptions catchen

fange nur die Exception die auch behandelt werden können bzw. dessen Behandlung sinnvoll ist.
"Behandeln" ist z.B. Loggen, dem Benutzer zeigen dass etwas nicht passt um es erneut zu versuchen, usw.

Irgendwo in der Anwendung (du schreibst nicht ob es eine Client- / Server-Anwendung ist) sollte allerdings ein "catch all"


try
{
    // Anwendungs-Startpunkt bei Client, z.B. in Main-Methode
}
catch (Exeception ex)
{
    // Loggen, etc.
}

durchgeführt werden, damit es keinen unbehandelten Fehler (unhandled exception) gibt, welche den Prozess terminieren würde.
(Achte auch bei Threads / Tasks darauf dass die nicht unbehandelt bleiben).

mfG Gü

24.02.2021 - 18:19 Uhr

Hallo Torni,

es ist eine Binärdatei und der Text den du siehst, wird nur vom Hex-Viewer so dargestellt, da es druckbare ASCII-Zeichen sind.
Daher kann der Suchtext mit entsprechender Kodierung in die binäre Darstellung gebracht und so direkt nach diesem gesucht werden.

Die Dateigröße ist recht überschaubar, daher am einfachsten alles aufeinmal einlesen. Das erspart komplizierteren Code bei dem z.B. in einem Buffer gelesen wird (od. mit Pipelines arbeitet).

Als Anstoss -- v.a. zum Suchen des Suchtextes:


using System;
using System.IO;
using System.Text;

Encoding encoding       = Encoding.GetEncoding("iso-8859-1");   // what's the correct encoding?
const string searchText = "XSA40_DATENSATZ";

ReadOnlySpan<byte> data         = File.ReadAllBytes("Torni.dat");
ReadOnlySpan<byte> searchPhrase = encoding.GetBytes(searchText);

while (!data.IsEmpty)
{
    int index = data.IndexOf(searchPhrase);

    if (index < 0)
    {
        Console.WriteLine("Nothing found :-(");
        break;
    }

    Console.WriteLine($"First occurrance of searchText at position {index}");

    // Move behind the found searchText
    if (data.Length < searchPhrase.Length) break;

    data = data.Slice(index + searchPhrase.Length);

    if (data.Length < 3) break;

    // Move to first int-data
    data = data.Slice(3);

    string value = encoding.GetString(data.Slice(0, 4));
    Console.WriteLine($"Value found: {value}");

    // I'll break here, as it's just a demo for you ;-)
    break;
}

Dabei wird Span verwendet, da sich so das Suchen mit IndexOf trivial gestaltet. Nachdem etwas gefunden wurde, wird mit Slice die Span "zerschnitten", so dass nur mehr der Rest übrig bleibt und dieser kann weiter untersucht werden.

Ganz klar ist mir noch nicht geworden wie und wo und welche Werte gelesen werden sollen. Aber das solltest du selbst schaffen 😉
Tipp: sollten Zahlen, etc. gelesen werden, so schau dir die BinaryPrimitives-Klasse an, welche perfekt mit Span harmoniert.

BTW: warum baust du in deinem Code einen String zusammen, nur damit dieser dann wieder aufgeteilt werden muss um diesen in ein Dictionary zu stopfen? Das kannst du doch direkt ohne den String auch machen? Aber wie erwähnt, mir ist noch immer nicht ganz klar was es werden soll.

mfG Gü

24.02.2021 - 16:41 Uhr

Hallo Torni,

Der Typ der Datei Testdat.dat kann nicht hochgeladen werden.

Z.B. als zip sollte gehen od. umbenennen in Testdat.txt.
Probier das einmal, dann zeig ich ein Demo wie es mit Span und Freu(n)de geht.

mfG Gü

24.02.2021 - 14:39 Uhr

Hallo Torni,

also der Suchtext steht als Plain-Text drin.

Als UTF-8 od. wie? Häng am besten so eine Beispiel-Datei an.
Wenns so ist wie ich mir vorstelle, dann lässt sich das elegant lösen -- aber bevor ich ein Demo zeige (da es doch nicht so gebräuchliche APIs sind) will ich gerne sehen wie es konkret ist, nicht dass ich was mache das den Punkt nicht trifft.

Außerdem hab ich oben noch mehr Fragen gestellt. Du willst Hilfe, also bitte ermögliche es den Helfern auch helfen zu können indem du die Fragen beantwortest.

mfG Gü

24.02.2021 - 10:11 Uhr

Hallo Torni,

der Suchtext "blabla"

Steht der Suchtext als Text od. auch binär in der Datei?

und nach diesem an Position z.B. +540 Zeichen steht das was ich auslesen muss..

Ist der Offset (hier die +540) gegeben od. wie werden diese ermittelt?
Das was du auslesen musst ist was? Ein struct od. etwas protokollbasiertes das geparst werden muss?

Ich frag deshabl, da es mit Span und MemoryMarshal ein paar sehr gute APIs für solche Fälle gibt.
Je nach Größe der Datei (wie groß ist die?) gibt es ev. mit dem SequenceReader eine weitere Alternative um das elegant und performant lesen zu können.

Aber bevor wir uns ev. in etwas verrennen beantworte bitte diese Fragen.
Am besten wäre wenn du ein Beispiel zeigen könntest wie die Datei ausschaut und was das Ergebnis sein soll.

mfG Gü

19.02.2021 - 12:07 Uhr

Hallo Crussy,

float und double sind Gleitkommazahlen, die nach IEEE 754 gespeichert werden.
float wird mit 32-bit gespeichert, während double mit 64-bit gespeichert wird, daher auch das "double" für "doppelte Genauigkeit". Da geht es v.a. darum wie die Zahlen und Ergebnisse gerundet werden. Somit können bei float 7-8 Dezimalstellen ohne Genauigkeitsverlust gespeichert werden, bei double sind es schon 15-16.

Der [FAQ] Double und Float: Fehler beim Vergleich und Rundungsfehler geht auf ein paar Eigenheiten dieser Gleitkommazahlen ein.

Wie erwähnt wird bei Operationen mit Gleitkommazahlen das "wahre Ergebnis" gerundet und somit ergeben sich zwangsläufig Rundungsfehler. Für viele Algorithmen spielen diese keine wesentliche Rolle, z.B. in der Thermodynamik ist es egal ob die Temperatur 273,1500001 K od. 273,1500002 K ist. Einen weiteren Ausflug in die Stabilität (Numerik) erspare ich dir hier 😉

Stell dir nun aber vor es geht um Bank-Geschäfte und bei jeder Transaktion würde ein Rundungsfehler passieren. Nach unzähligen solcher Transaktionen und einer bestimmten Zeit könnten die Rundungsfehler so groß werden, dass die Bilanzen nicht mehr stimmen und das spielt eine wesentliche Rolle. Daher ist sind die o.g. Gleitkommazahlen ungeeignet und deshalb wurde der Datentyp decimal erfunden. Dieser besitzt keine Rundungsfehler und ist somit für Finanz-Mathematik die geieignete Wahl. Allerdings ist das Rechnen mit decimal aufgrund der Genauigkeitsanforderungen und des Wert-Bereichs nicht so performant wie mit den Gleitkomma-Typen double / float und tw. auch nicht anwendbar (da der Wert-Bereich über-/unterschritten wird).

Zusammengefasst:
Finanzmathematik -> decimal
Sonst -> double, außer Anforderungen an die Genauigkeit sind nicht sehr hoch dass float.

Was jedoch "nicht sehr hoch" bedeutet ist von Aufgabe zu Aufgabe verschieden, aber siehe oben bei den Dezimalstellen.

mfG Gü

19.02.2021 - 10:23 Uhr

Hallo Crussy,

Präfix bedeutet "Vorsilbe", Postfix ist die "Nachsilbe". Bezogen aufs Programmieren ist das v.a. in Bezug auf Inkrementoperator.


int i = 42;
i = i + 1;

kann gekürzt werden zu


int i = 42;
i += 1;

und weiter gekürzt zu


int i = 42;
++i;

Hier wurde der Präfix-Inkrementoperator verwendet. Der Unterschied zwischen Präfix-/Postfix-Operator ist das Ergebnis:


int i = 42;
int a = i++;    // a hat den Wert von i (=42) erst danach wird i inkrementiert und hat danach den Wert 43
int b = ++i;    // zuerst wird i inkrementiert und hat den Wert 43+1=44, danach wird dieser Wert b zugewiesen so dass b = 44 ist

mfG Gü

12.02.2021 - 13:00 Uhr

Hallo Th69,

Dann sollte es doch kein Problem sein, beim Parsen den passenden Titel aus dem Link (anhand der Thread-ID) zu holen?!

ist es auch nicht. Nur bisher sind wir davon ausgegangen dass die Urls aus der Adressleiste einfach kopiert werden, also z.B. https://mycsharp.de/forum/threads/26594/wie-poste-ich-richtig und nicht eine manuelle gekürzte Url wie https://mycsharp.de/forum/threads/26594 in den Beitrag kopiert wird.

Würde -- auch welchen Gründen auch immer -- das Nachschlagen in der DB nicht klappen, so würde der "Slug" wie wie-poste-ich-richtig als Link-Text verwendet, da dies immer noch besser als die rohe Url ist.

Die Änderung dafür ist schon parat.

Nur aus Interesse: warum "streubst" du dich gegen diese Art der Urls? (vllt. ist mein Eindruck jetzt falsch).

mfG Gü

11.02.2021 - 19:18 Uhr

Hallo Th69,

eigentlich sollte der Titel übernommen werden -- zumindest jener Titel wie er in der DB für den Thread steht.
Kannst du bitte ein Beispiel geben damit das geprüft werden kann? Ich schau auch in den Logs nach ob ich dort etwas finde.

Z.B. https://mycsharp.de/forum/threads/26594/hinweis-wie-poste-ich-richtig wird korrekt übersetzt.
Kann es sein dass du einen "alten Link" hattest? Diese gehen nicht.

Edit: sehe etwas in den Logs das passen könnte. Es geht um https://mycsharp.de/forum/threads/71995 (dein Parser).

mfG Gü

03.02.2021 - 14:05 Uhr

Hallo hannebambellino,

Ich habe eine csv Datei, die 12 Felder breit ist und 9 tief.

Genau die wäre interessant -- Beispieldaten und was heraus kommen soll, also wie du dir das Resultat vorstellst.
Dann werden wir schon einen Lösung finden 😉

BTW: bitte verwendne die Code-Tags -- [Hinweis] Wie poste ich richtig? Punkt 6.

mfG Gü

03.02.2021 - 13:01 Uhr

Hallo hannebambellino,

damit wir alle das gleiche Verständnis vom Problem haben, kannst du eine kleines Demo zeigen?

mfG Gü

01.02.2021 - 16:24 Uhr

Hallo degri2006,

ich kann das geschilderte Verhalten nicht reproduzieren.
Welche .NET Version verwendet du und welche Culture (normal jene vom Betriebssystem, also de-DE od. de-AT (wie bei mir)).


using System;

string line = "$a=\"blablablablablablablabla\x00\" wide nocase";

string a = line.Split("=")[0];
string b = line.Split("=")[1];

Console.WriteLine(line);
Console.WriteLine(a);
Console.WriteLine(b);

liefert


$a="blablablablablablablabla " wide nocase
$a
"blablablablablablablabla " wide nocase

Die \0 werden / können so nicht dargestellt werden.

BTW: statt "=" (ist ein String) ist es besser die char-Überladung zu verwenden, also


string a = line.Split('=')[0];
string b = line.Split('=')[1];

Hier ist (unter .NET 5.0 und de-AT) das Ergebnis gleich, aber wegen Globalization APIs use ICU libraries on Windows könnte es einen Unterschied machen.

mfG Gü

27.01.2021 - 17:32 Uhr

Hallo MrSparkle,

ist XSL-FO eine Option?
Würde zu Templates + Daten ganz gut passen und wenn die "Einstiegshürde" geschafft ist, so ist es relativ trivial zu handhaben. Z.B. mit https://www.nuget.org/packages/Fonet.Standard/

PS: mich wundert es auch (immer wieder) dass es für den de-facto Dokument-Standard PDF keine vernüftigen Lösungen gibt.

mfG Gü

19.12.2020 - 10:15 Uhr

Hallo Mattes80,

versetzt dich bitte in die Lage von jemanden der nicht weiß worum es geht und lies die Frage.

Welche Code behind?
PC <-> Maschine -- ich kann raten was gemeint ist, aber ist es das dann wirklich?

Wie willst du das "Internet" sperren? Von außen od. soll das der Mitarbeiter am PC an der Maschine einfach sperren / entsperren können?

Welcher Betriebssystem ist vorhanden?

Also bitte konkretere Infos in der Frage, dann ist die Chance auf konkretere Antworter auch höher.

mfG Gü

17.12.2020 - 10:27 Uhr

Hallo OXO,

ganz verstanden hab ich nicht was du optimieren willst, aber ich denke es ist Suche nach "Knappsack" bzw. Suche nach "Rucksack".

mfG Gü

05.12.2020 - 16:31 Uhr

Hallo Magier69,

anfreunden damit...

Ja mach das und probiers einfach aus, dann kannst Freude damit haben das es viel umständlichen Code erspart.

Sonst frag einfach wieder im Forum nach 😉

mfG Gü

05.12.2020 - 16:15 Uhr

Hallo Magier69,

bei deinen Tests hat es keinen Vorteil.

Stell dir aber vor du willst eine IO-Operation (Input, Output) wie z.B. Netwerkzugriffe ala Datenbankabfrage, Web-Request, etc. durchführen so würde bei


var result = service.GetData(...);
UseResult(result);

der ausführende Thread blockiert werden, bis das Ergebnis vorliegt. Das ist nicht ideal.

Daher gibt es asynchrone IO-Vorgänge, bei denen ein Task erzeugt wird und keinen Thread blockiert, sondern bei "Abschluss" des IO-Vorgangs ein sogenannter IO-Thread vom ThreadPool verwendet wird um das "Callback" durchzuführen. Hier eignet sich async/await, da eleganter Code geschrieben werden kann der leserlich ist.


var result = await service.GetDataAsync(...);
UseResult(result);

service.GetDataAsync gibt dabei eine Task zurück, der C#-Compiler erkennt das async/await und erstellt für dich Code der sehr grob analog zu


Task resultTask = service.GetDataAsync(...);
resultTask.ContinueWith(t => UseResult(t.Result));

ist. Da ist der "await Code" schon leserlicher, v.a. wenn mehrere awaits in einer Methode sind.

mfG Gü

04.12.2020 - 12:54 Uhr

Hallo,

ich würde lieber auf die Original-Ankündigung verweisen anstatt zu einem Artikel der im Grunde nur die Info zusammenfasst und selbst auch auf diesen Blog-Beitrag von MS verweist.

mfG Gü

03.12.2020 - 11:43 Uhr

Hallo,

Randbemerkung: https://themesof.net/ ist eine Blazor-Anwendung.

mfG Gü

02.12.2020 - 16:51 Uhr

Hallo,

ein Bug sollte sich im Idealfall durch (Unit-) Tests reproduzieren lassen und falls nicht, so sollte dafür ein Test erstellt werden. Auch damit es später einmal zu keiner Regression kommen kann.

Gibt es jedoch bereits Tests mit passenden Test-Argumenten und der Bug lässt sich dennoch nicht reproduzieren, so mag es u.U. auch am Test-Code selbst liegen.


actual.Should().BeSameAs(actual);

Notiz aus dieser Geschichte:
In solch einem Fall durch bewusste Fehl-Eingaben für den Test, so dass dieser zwangsweise fehlschlagen muss, eine Validierung vom Test-Code vornehmen.
Schlägt der Test nämlich nicht fehl, so ist der Test-Code faul.

Weitere Infos dazu:
Testgetriebene Entwicklung
What is red/green testing?

mfG Gü

27.11.2020 - 21:39 Uhr

Hallo aloqqq,

multidimensionales Array

Muss es ein multidimensionales Array sein?
"Jagged arrays" werden von der .NET Runtime besser unterstützt, falls Leistung ein Kriterium ist.

Auch bieten die jagged Arrays die Möglichkeit die Matrix als Tupel von Spaltenvektoren zu speichern -- du hast das Layout in der Hand. Für dein Beispiel wäre es dann einfach den Vektor in die jeweilige Spalte zu kopieren.


int[] col0 = { 1, 2, 3, 4 };
int[] col1 = { 5, 6, 7, 8 };

int[][] matrix = new int[2][];
matrix[0]      = new int[col0.Length];
matrix[1]      = new int[col1.Length];

col0.CopyTo(matrix[0], 0);
col0.CopyTo(matrix[1], 0);

Es ist auch möglich die Matrix nur in einem (1d) Array zu speichern, so dass einfach Spaltenvektor and Spaltenvektor gehängt wird. Der Zugriff erfolgt dann via entsprechenden Indexer. Grob z.B. so


using System;

int[] col0 = { 1, 2, 3, 4 };
int[] col1 = { 5, 6, 7, 8 };

Matrix matrix = new(4, 2);
matrix.SetColumnVector(col0, 0);
matrix.SetColumnVector(col1, 1);
matrix.Print();

public class Matrix
{
    private readonly int[] _storage;
    private readonly int   _rows;
    private readonly int   _cols;

    public Matrix(int rows, int cols)
    {
        // Argumente sollten hier validiert werden, auch ist auf potentiellen Overflow
        // (durch die Multiplikation) zu achten!
        int size = rows * cols;
        _storage = new int[size];
        _rows    = rows;
        _cols    = cols;
    }

    // Wir verwenden ein "ref return", es wird also die Referenz zum Matrix-Element
    // zurückgegeben. Das erspart uns die Implementierung eines "setters".
    public ref int this[int i, int j]
    {
        get
        {
            if (i >= _rows) throw new ArgumentOutOfRangeException(nameof(i));
            if (j >= _cols) throw new ArgumentOutOfRangeException(nameof(j));

            // Matrix wird spaltenweise (als Tupel von Spaltenvektoren)
            // gespeichert
            int index = j * _rows + i;
            return ref _storage[index];
        }
    }

    public void SetColumnVector(int[] vector, int j)
    {
        if (vector.Length != _rows) throw new ArgumentException(/* ... */);

        int index = j * _rows;
        Array.Copy(vector, 0, _storage, index, vector.Length);
    }

    public void Print()
    {
        for (int i = 0; i < _rows; ++i)
        {
            for (int j = 0; j < _cols; ++j)
            {
                Console.Write($"{this[i, j]}\t");
            }
            Console.WriteLine();
        }
    }
}

mfG Gü

16.11.2020 - 21:28 Uhr

Hallo MMazi,

ja, ist das gleiche -- nur halt in deutscher Sprache.

Aber probiers doch einfach aus (mit dem Draufklicken) 😉

mfG Gü

14.11.2020 - 10:58 Uhr

Hallo nochmal,

das muss ich noch ergänzen.

Aaron Robinson, der Autor dieses Features in .NET, hat https://github.com/AaronRobinsonMSFT/DNNE erstellt und baut auf dem Vorgenannten auf. Hier ist es möglich per UnmanagedCallersOnlyAttribute den nativen Export zu erzeugen, aber nicht in .NET 5 selbst.

mfG Gü

14.11.2020 - 10:53 Uhr

Hallo dannoe,

danke für den Link zum Artikel. Aber dieser ist wirklich schlecht recherchiert und suggiert dass es genügt UnmanagedCallersOnlyAttribute auf eine statische Methode zu setzen und gut ist es. Das ist bei Weitem nicht so (und der Autor sollte sich besser mit anderen Themen beschäftigen).

UnmanagedCallersOnlyAttribute teilt dem JIT mit, dass die so markierte Methode ausschließlich von nicht-verwaltetem Code (~ nativen Code) aufgerufen wird. Somit wird als "function pointer" (erwähnt auch in voriger Antwort) eine leichtgewichtigere Version erstellt, als wenn die Methode auch von managed Code aufgerufen werden würde.

Der wesentliche Hinweis zu Write a custom .NET Core host to control the .NET runtime from your native code fehlt im Artikel, denn somit sind die "native exports" möglich (aber auch schon vor .NET 5, ich glaube fast ab .NET Fx 1.0, also seit Beginn an nur wurde es "vereinfacht" und performanter gemacht).

mfG Gü

14.11.2020 - 10:41 Uhr

Hallo pollito,

falschen Suchbegriffe

mit ".net 5 native exports" wirst du fündig.

Ganz trivial ist die Sache aber nicht, da die CLR selbst gehostet werden muss, anders kann JIT-kompilierter IL-Code auch nicht ausgeführt werden.
Die Pakete, die du finden wirst, machen das nicht anders, nur teilweise eben für dich.

Ich finde die zitierte Aussage vom Artikel ein wenig irreführend bzw. verspricht sie mehr als es ist.

Der "klassische Weg" mit nativen Anwendungen zu kommunizieren bleibt dass .NET eine native Bibliothek aufruft und der native Teil per Callback wieder in .NET zurückrufen kann.
Der Callback war bisher ein Delegate, das wird sich aber mit "function pointers" (von C# 9) ändern.

mfG Gü

13.11.2020 - 18:05 Uhr

Hallo,

es gibt in VS auch eine nette / praktische "search bar".
Ctrl + Q --> Eingabe (hier "solution explorer") --> die Eregbnisse passen meist

mfG Gü

06.11.2020 - 14:38 Uhr

Hallo,


private static string GetXyzInstanceString()	// Xyz changed from actual name
{
	// We are going to hardcode the value here to 3 (a random number) so that we don't have to
	// ...
	int id = 3;
	return id.ToString(CultureInfo.InvariantCulture);
}

wurde geändert zu


private static string GetXyzInstanceString()	// Xyz changed from actual name
{
	// We are going to hardcode the value here to 3 (a random number) so that we don't have to
	// ...
	return "3";
}

Immer KISS berücksichtigen.

mfG Gü

24.10.2020 - 11:00 Uhr

Hallo BerndFfm,

die Ursache / Lösung der anderen ist die sauberste Art und Weise das zu handhaben.
Tipp: VS Performance Profiler -> .NET Object Allocation Tracking, dort kannst du die "Wurzeln" betrachten.

Sonst ev. auch Weak References.

mfG Gü

24.10.2020 - 10:55 Uhr

Hallo,

Zitat von: mycsharp.de ist nun auf Azure umgezogen
Wir haben damit eine Basis, die es uns insgesamt vereinfacht langfristig von phpBB ganz weg zu kommen, woran wir parallel bereits arbeiten.

Ob auch ein neues Frontend geplant ist, weiß ich nicht.

Technisch gesehen wird das Frontend neu, basiert wie das Backend auf ASP.NET Core 5 und Razor.
Das Erscheinungsbild bleibt aber (zumindest vorläufig) sehr nahe am bisherigen.

Nähere Infos aber dann wenn es soweit ist.
Und gleich vorweg: es ist dann soweit, wenn wir glauben dass es soweit ist 😉

mfG Gü

10.10.2020 - 11:25 Uhr

Hallo Sebrahi,

da kannst du jede Datenbank verwenden (außer Access, denn das ist keine Datenbank).
Nimm SQL Server Express. Da ist auch das "Tooling" für VS super.

mfG Gü

08.10.2020 - 22:05 Uhr

Hallo MrSparkle,

auf eigenen Vektor-Implementierungen

Angenommen diese eigenen Vektoren wären structs. Dann ist es auch möglich diese in einen HW-Vector zu lesen. Z.B. (ab .NET Core 3.1):


using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;

public static class MyVectorExtensions
{
    public static Vector256<double> ToVector256(this My3dVector vector)
    {
        return Unsafe.As<My3dVector, Vector256<double>>(ref vector);
    }
}


public struct My3dVector
{
    public double X;
    public double Y;
    public double Z;
}

(Gleiches ginge auch für Vector3)

Unsafe.As<TFrom, TTo> entspricht einem reinterpret_cast in C++.
Achtung! Hier ist nicht nur die Klasse Unsafe, sondern auch die Verwendung.* wird Unsafe verwendet, so kann der JIT keine Typprüfungen durchführen

  • im Beispiel hier kann der Vector256<double> 4 Elemente aufnehmen, die Struct definiert aber nur 3, daher ist das 4. Vector256<double>-Element Müll
  • wegen letztem Punkt wird über die Grenzen der Struct hinausgelesen und das kann zu einer AccessViolation führen -- es ist zwar sehr unwahrscheinlich dass das tatsächlich passieren mag, aber es soll dennoch darauf hingewiesen werden

Würde ein Vector128<double> verwendet werden, so hätten nur 2 doubles-Platz und somit kann die gesamte Struct nicht gelesen werden.

Diese Art des Speichern von 3d-Vektoren wird Array of Structures genannt und ist eher ungünstig, da entweder zuviel od. zuwenig gelesen wird.
Auch sind etliche Operationen nur unhandlich durchzuführen.

Daher gibt es auch die Möglichkeit der Structure of Arrays, welche diese Nachteile nicht haben und meist günstigere Implementierungen nach sich ziehen.
Allerdings bedeutet das oft auch, dass wesentliche Teile vom Code angepasst werden müssten.

Wenn man das als SSE umschreibt

Mit dem verlinkten Artikel musst du aufpassen, denn da wird float verwendet (zu erkennen an der s postfix der Befehlen (s...single, d...double)).
Für double müsste dann AVX (256bit) verwendet werden und da kann es mit dem mischen (shuffle) problematisch werden, denn AVX ist "eigentlich" nur 2xSSE und d.h. ein Shuffle über die "Lanes" geht nur mittels "Permute" 😉 (ich will damit ausdrücken: es wird komplizierter).

Das Kreuzprodukt ist aber (ähnlich wie Matrizenmultiplikation) ohnehin ein schwieriges Beispiel. Aber bei deinen Anwendungen wohl eine sehr häufig verwendet Operation.

mfG Gü

02.10.2020 - 10:54 Uhr

Hallo MrSparkle,

JitIntrinsicAttribute RyuJIT ist der aktuelle JIT-Compiler von .NET und wie so gut wie jeder Compiler arbeitet auch dieser in "Phasen". Ein der erste Phasen ist das "Importieren".

Mit dem JitIntrinsicAttribute (bzw. nach dem Umbenenne nur mehr IntrinsicsAttribute) wird dem RyuJIT mitgeteilt, dass der Typ od. die Methode welches so attributiert ist, speziell zu behandeln ist. D.h. es wird nicht der dort angegebene (IL-) Code verwendet, sondern der JIT importiert spezialisierten Code.

Das ist ein Workaround und nicht mehr, mit dem bestimmte Einschränkungen seitens C# / IL umgangen werden.

Ein Beispiel dazu ist die Implementierung von Span<T>.
Aktuell ist es nicht möglich in einer ref struct ein Feld zu haben das ebenfalls eine ref ist (sollte aber mit C# 10 kommen).
Daher wurde mittels eines ByReference diese Beschränkung umgangen und um möglichst effizienten Maschinencode erzeugen zu können benötigt der RyuJIT eine Sonderbehandlung und genau diese wird mit Intrinsic angegeben.

Da Intrinsic ein Implementierungsdetail ist, wurde es auch als internal deklariert.

Das Bestreben vom .NET-Team ist sowohl C# als auch ggf. IL / allgemeiner: die Plattform so weiter zu entwickeln dass dieser Workaround nicht nötig ist. (Da mit C# geschriebener Code wesentlich portabler ist als Spezialisierungen in C++).

Anm.: CoreRT war / ist hierzu ein "Versuchsfeld" das Vieles direkt in C# implementierte und auf native Implementierungen -- sofern möglich -- verzichtet. Teile davon werden nach und nach zu .NET (Core) portiert.

IntrinsicAttribute geben sollte, mit dem man Methoden für eine spezielle Optimierung durch den JIT-Kompiler markieren kann

Ich denke das wurde so um 2015 verlautbart und war wohl eher ein Wunsch als Wirklichkeit.
Angelehnt war das vermutlich an die "auto vectorziation" Möglichkeiten moderner nativer Compiler (wie gängige C/C++ Compiler), die aber auch nicht jeden Code behandeln können, sondern eher nur einfachen schleifenbasierten Code durch Abrollen (Unrolling) und Anwendung von SIMD-Registern.

Einem JIT steht wegen dem "just in time" diese Möglichkeit nicht zur Verfügung, da die auto-vectorization zeitintensiv ist und somit in der knappen dem JIT zur Verfügung stehenden Zeit nicht durchführbar ist.

Nun hat der aktuelle RyuJIT ab .NET Core 2.1 die Möglichkeit der "Tiered Compilation", d.h. es wird mehrstufig kompiliert. In Tier-0 gibt es kaum Optimierungen, so dass der Programmstart zügig voranschreiten kann. Wird eine Methode mehrmals aufgerufen, so dass sie "heiß" wird und wenn diese Aufrufe nach der Startphase ist, so wird der Code dieser Methode mit mehr Optimierungen in Tier-1 kompiliert.
Hier gibt es aktuell verschiedene Diskussionen über weitere Möglichkeiten um noch "optimaleren" Code zu generieren. Dazu zählen Profilinformationen die in Tier-0 gesammelt werden, eine weitere Optimierungsstufe mit Tier-2 usw. Konkret ist hier noch nichts.

Für einen hypothetischen Tier-2 könnte auto-vectorization angewandt werden.
Aber wie vorhin erwähnt klappt das eigentlich nur für simple Schleifen recht gut. Sobald Tensoren höherer Stufe behandelt werden, fehlt dem Compiler einfach das Wissen über die genaue Intention was der Programmierer will und wie die Speicherzugriffe, etc. genau zu erfolgen. Um das zu lösen gibt es mMn zwei Möglichkeiten:* eine angepasstere Programmiersprache für Tensor-Rechnung (und / oder Fortran verwenden 😉)

  • den maschinennahen Teil mit HW-Intrinsics (HW...hardware) selbst programmieren

Auch wenn aktuelle C/C++ Compiler auto-vectorization, etc. können, werden "kritische Bereiche" nach wie vor mit Intrinsic (händisch) programmiert, da dies schon ein großer Schritt nach vorne vom Programmieren in Assembler ist.
C# / .NET wird hier keine Sonderrolle einnehmen können, noch dazu mit "time constraints", welchen der JIT -- unabhängig vom Tiering -- unterliegt.

Das Versehen einer Methode od. eine Types mit einem Attribut ist bei Weitem nicht ausreichend um spezielle Optimierungen zu ermöglichen bzw. würde das Ergebnis wohl nie so gut werden, als wenn der Programmierer, der die Aufgabe (hoffentlich) genau versteht, selbt optimierten Code schreibt. Dazu wird das Thema einfach schnell sehr komplex, da auch die super-skalaren CPUs mit ihren Pipelines, CPU-Caches, jede Menge Latenzen usw. einspielen. Ohne Profiler auf Maschinencode-Ebene und Betrachtem vom erzeugten Maschinencode geht es hier nicht mehr und das kann mühselig werden (außer man empfindet daran Gefallen 😉).

Ich würde diese Vorstellung als Zukunftsmusik abtun, die in den nächsten Jahren in .NET wohl nicht spielen wird und in nativen Sprachen wohl auch nur leisen Töne von sich geben wird.

Analog dazu gibt es aktuell auch kaum ein Projekt das wirklich GPU-Code aus herkömmlichen Code automatisch erzeugen kann, der "sauber" läuft und an händisch geschriebenen (z.B. CUDA) GPU-Code herankommt.

Der von dir verlinkte Blog-Beitrag über die HW-Intrinsics ist zwar ein Jahr alt, aber vom Inhalt her aktuell.
Die HW-Intrinsics sind Teil der .NET-API-Landschaft und da ändert sich dann nichts mehr (genauso wie ArrayList seit .NET 1.0 immer noch dabei ist).
Ein paar Verwendungsmuster haben sich herauskristallisiert, aber im Wesentlichen passt der Inhalt dieses Blogs.

alle wichtigen Methoden in allen relevanten Befehlssätzen neu zu implementieren müssen, scheint mir unverhältnismäßig mehr Aufwand zu sein.

Es gibt 2 Arten von vektor-gestütztem Code in .NET* Vector2, Vector3, Vector3 und Vector<T> aus System.Numerics

  • Vector128, etc. aus System.Runtime.Intrinsics

Grob gesprochen sind letztere nur Typen, welche dann mittels den Methoden aus Sse2, Avx2, AdvSimd usw. bearbeitet werden.
D.h. auch dass es je nach Zielplattform und CPU-Unterstützung getestet werden muss um so unterschiedliche Code-Pfade haben zu können. Einen Software-Fallback, falls es keine Unterstützung gibt, sollte auch vorhanden sein.
(Außer du weißt dass der Code eh nur auf einer bekannten Plattform z.B. auf einer Intel i7 CPU läuft, dann kannst du diese Test sparen).

Die Typen aus System.Numerics bieten Methoden zum Bearbeiten an und übernehmen die "Unterstützungs"-Test für dich und haben auch einen Software-Fallback implementiert.
Allerdings ist -- zumindest aktuell* -- der erzeugte Maschinencode mit den HW-Intrinsics meist besser. Zudem können mit den HW-Intrinsics, hier am Beispiel von x64 erklärt, bei Vektoren zuerst "AVX-Schritten" (256 bit), dann der Rest in "SSE-Schritten" (128 bit) und der Rest skalar verarbeitet werden, währen die SN-Vektoren nur eine der Vektor-Größen (entweder AVX falls unterstützt von der CPU, sonst SSE) kennen.

Ein Vorteil der HW-Intrinsics ist auch, dass es viele Referenz-Implementierungen für Problem in C++ mit intrinsics gibt und diese sind somit einfacher zu C# zu portieren.

Klar erhöht sich der Aufwand so (fast immens), aber die Ziel-Gruppe der HW-Intrinsics ist auch nicht das breite Publikum sondern eher die Nische, welche "bestmögliche Geschwindigkeit" haben will (und dazu zählen die .NET Innerein selbst).

* es ist geplant die Implementierungen von System.Numerics-Vektoren neu zu implementieren auf Basis der HW-Intrinsics, die erst später Einzug in .NET hielten als die SN-Vektoren die schon länger da sind

Da ich viel mit 3D-Grafik zu tun habe, wäre die Kompilierung in CPU-spezifische Befehlssätze sehr sinnvoll.

Schau dir dazu einmal Vector3 und Vector4 genauer an.
Die wurden für solche Szenarien eingeführt und haben viele Anleihen von DirectX-Math (od. wie das genau heißt) genommen.
Diese Vektoren können auch als Felder in eigenen Typen verwendet werden (die HW-Intrinsics Vektoren übrigens auch).
Auf ein Umschreiben / Anpassen deines Codes wirst du da nicht herumkommen (wie erwähnt schaffen das nicht einmal native Compiler die genügend Zeit dafür haben).

um eigenen Code JIT-optimieren zu können?

Im Release-Build führt der JIT seit jeher Optimierungen durch.
(Ich weiß aus dem Kontext, dass du nicht danach gefragt hast).

mfG Gü

25.09.2020 - 16:04 Uhr

Hallo ck82,

ich stimme Abt da ganz zu.

Daher wird auch nicht "einfach so" eine Kopie erstellt.

Das ist eben die Krux dabei, dass beide Threads (der Main-Thread, sowie jener der die Aktion von Task.Run mit einem ThreadPool-Thread ausführt) auf dasselbe Objekt arbeiten und du nicht bestimmen kann wer wann welche Ändeurng zuerst durchführt. Es ist somit durchaus möglich, dass in den Daten deines Objekts Müll entsteht. Das ist die von Abt erwähnte "Race Condition".

Abhilfen gibt es dafür ein paar:* Thread-Synchronisierungen (suche mal danach, da gibt es Lektüre fürs WE -- Vorzugsweise: Basic Synchronization aus Threading in C# / Joseph Albahari)

  • immutable Typen verwenden, d.h. Typen die nach der Instanzierung nicht mehr geändert werden können und somit gibt es kein Race
    (Anm.: das ist mit ein Grund warum mit C#9 Records eingeführt werden, neben dem weniger Tipparbeit für Datenklassen)

  • asynchron arbeiten, aber ohne gleichzeitige Zugriffe auf das Objekt, z.B. mittels einer Pipeline in der das Objekt von "Station zu Station" gereicht wird

Aber berücksichtige

erzählst, was Dein Vorhaben ist

mfG Gü