Skip to content

Commit 044b1a4

Browse files
committed
Revise L24
1 parent 29d33df commit 044b1a4

2 files changed

Lines changed: 150 additions & 19 deletions

File tree

24_Tasks.md

Lines changed: 145 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,105 @@ import: https://raw.githubusercontent.com/TUBAF-IfI-LiaScript/VL_Softwareentwick
3333

3434
---------------------------------------------------------------------
3535

36-
## Logging
36+
## Exkurs - Paketmanagement
37+
38+
> **Merke:** Erfinde das Rad nicht neu!
39+
40+
Wie schaffen es erfahrene Entwickler innerhalb kürzester Zeit Prototypen mit beeindruckender Funktionalität zu entwerfen? Sicher, die Erfahrung spielt hier eine große Rolle aber auch die Wiederverwendung von existierendem Code. Häufig wiederkehrende Aufgaben wie zum Beispiel:
41+
42+
+ das Logging
43+
+ der Zugriff auf Datenquellen
44+
+ mathematische Operationen
45+
+ Datenkapselung und Abstraktion
46+
+ ...
47+
48+
werden bereits durch umfangreiche Bibliotheken implementiert und werden entsprechend nicht neu geschrieben.
49+
50+
Ok, dann ziehe ich mir eben die zugehörigen Repositories in mein Projekt und kann die Bibliotheken nutzen. In individuell genutzten Implementierungen mag das ein gangbarer Weg sein, aber das Wissen um die zugehörigen Abhängigkeiten - Welche Subbibliotheken und welches .NET Framework werden vorausgesetzt? - liegt so nur implizit vor.
51+
52+
Entsprechend brauchen wir ein Tool, mit dem wir die Abhängigkeiten UND den eigentlichen Code kombinieren und einem Projekt hinzufügen können.
53+
`NuGet` löst diese Aufgabe für .NET und schließt auch gleich die Mechanismen zur Freigabe von Code ein. NuGet definiert dabei, wie Pakete für .NET erstellt, gehostet und verarbeitet werden.
54+
55+
Ein `NuGet`-Paket ist eine gepackte Datei mit der Erweiterung `.nupkg` die:
56+
57+
+ den kompilierten Code (DLLs),
58+
+ ein beschreibendes Manifest, in dem Informationen wie die Versionsnummer des Pakets, ggf. der Speicherort des Source Codes oder die Projektwebseite enthalten sind sowie
59+
+ die Abhängigkeiten von anderen Paketen und dessen Versionen
60+
enthalten sind
61+
Ein Entwickler, der seinen Code veröffentlichen möchte generiert die zugehörige Struktur und läd diese auf einen `NuGet` Server. Unter dem [Link](https://www.nuget.org/) kann dieser durchsucht werden.
62+
63+
**Anwendungsbeispiel: Symbolisches Lösen von Mathematischen Gleichungen**
64+
65+
Eine entsprechende Bibliothek steht unter [Projektwebseite](https://symbolics.mathdotnet.com/). Das Ganze wird als `Nuget` Paket gehostet [MathNet](https://www.nuget.org/packages/MathNet.Symbolics/).
66+
67+
Unter der Annahme, dass wir `dotnet` als Buildtool benutzen ist die Einbindung denkbar einfach.
68+
69+
```
70+
dotnet new console -o SymbolicMath
71+
cd SymbolicMath
72+
dotnet add package MathNet.Symbolics
73+
Determining projects to restore...
74+
Writing /tmp/tmpNsaYtc.tmp
75+
info : Adding PackageReference for package 'MathNet.Symbolics' into project '/home/zug/Desktop/Vorlesungen/VL_Softwareentwicklung/code/16_Testen/ConditionalBuild/ConditionalBuild.csproj'.
76+
info : GET https://api.nuget.org/v3/registration5-gz-semver2/mathnet.symbolics/index.json
77+
...
78+
```
79+
80+
Danach findet sich in unserer Projektdatei `.csproj` ein entsprechender Eintrag
81+
82+
```xml
83+
<Project Sdk="Microsoft.NET.Sdk">
84+
85+
<PropertyGroup>
86+
<OutputType>Exe</OutputType>
87+
<TargetFramework>net8.0</TargetFramework>
88+
</PropertyGroup>
89+
90+
<ItemGroup>
91+
<PackageReference Include="MathNet.Symbolics" Version="0.24.0" />
92+
</ItemGroup>
93+
</Project>
94+
```
95+
96+
```csharp PreprocessorConsts.cs
97+
using System;
98+
using System.Collections.Generic;
99+
using MathNet.Symbolics;
100+
using Expr = MathNet.Symbolics.SymbolicExpression; // Platzhalter für verkürzte Schreibweise
101+
102+
class Program
103+
{
104+
static void Main(string[] args)
105+
{
106+
Console.WriteLine("Beispiele für die Verwendung des MathNet.Symbolics Paketes");
107+
var x = Expr.Variable("x");
108+
var y = Expr.Variable("y");
109+
var a = Expr.Variable("a");
110+
var b = Expr.Variable("b");
111+
var c = Expr.Variable("c");
112+
var d = Expr.Variable("d");
113+
Console.WriteLine("a+a+a =" + (a + a + a).ToString());
114+
Console.WriteLine("(2 + 1 / x - 1) =" + (2 + 1 / x - 1).ToString());
115+
Console.WriteLine("((a / b / (c * a)) * (c * d / a) / d) =" + ((a / b / (c * a)) * (c * d / a) / d).ToString());
116+
Console.WriteLine("Der zugehörige Latex Code lautet " + ((a / b / (c * a)) * (c * d / a) / d).ToLaTeX());
117+
}
118+
}
119+
```
120+
```-xml PreprocessorConsts.csproj
121+
<Project Sdk="Microsoft.NET.Sdk">
122+
<PropertyGroup>
123+
<OutputType>Exe</OutputType>
124+
<TargetFramework>net8.0</TargetFramework>
125+
</PropertyGroup>
126+
<ItemGroup>
127+
<PackageReference Include="MathNet.Symbolics" Version="0.24.0" />
128+
</ItemGroup>
129+
</Project>
130+
```
131+
@LIA.eval(`["Program.cs", "project.csproj"]`, `dotnet build -nologo`, `dotnet run -nologo`)
132+
133+
134+
## Exkurse: Logging
37135

38136
Wie arbeiten wir bisher in Bezug auf Textausgaben?
39137

@@ -76,6 +174,20 @@ Dieses Vorgehen kann auf Dauer ziemlich nerven ...
76174

77175
> Lösung: Verwenden Sie ein Logging Framework, z.B. NLog - ein Logging-Framework für .NET-Anwendungen!
78176
177+
| **Merkmal** | **Beschreibung** | **`print()`** | **Logging-Framework** |
178+
| ---------------------- | ----------------------------------------------------------------------------- | ------------- | --------------------- |
179+
| **Zentrale Steuerung** | Konfiguration und Steuerung der Ausgabe zentral möglich |||
180+
| **Log-Level** | Nachrichten können je nach Wichtigkeit kategorisiert werden |||
181+
| **Formatierung** | Ausgaben können standardisiert formatiert werden (z. B. mit Zeitstempel) |||
182+
| **Dateihandling** | Logs können automatisch in Dateien geschrieben und rotiert werden |||
183+
| **Mehrere Ausgaben** | Gleichzeitige Ausgabe an Konsole, Datei, Netzwerk usw. |||
184+
| **Thread-Sicherheit** | Gleichzeitige Ausgaben mehrerer Threads führen nicht zu vermischten Zeilen |||
185+
| **Integration** | Logs können mit externen Tools (z. B. Logserver, Dashboards) verwendet werden |||
186+
187+
188+
{{1-2}}
189+
***********************************************************************
190+
79191
NLog:
80192

81193
+ ermöglicht das Protokollieren von Informationen, Warnungen, Fehlern und anderen Ereignissen,
@@ -121,6 +233,8 @@ public class Program
121233
+ https://github.com/NLog
122234
+ https://riptutorial.com/nlog
123235

236+
***********************************************************************
237+
124238
## Rückblick: Multithreading
125239

126240
Die prozedurale/objektorientierte Programmierung basiert auf der Idee, dass ausgehend von einem
@@ -147,9 +261,11 @@ class Program
147261
```
148262
@LIA.eval(`["main.cs"]`, `mcs main.cs`, `mono main.exe`)
149263

150-
An dieser Stelle spricht man von **synchronen** Methodenaufrufen. Das
264+
> An dieser Stelle spricht man von **synchronen** Methodenaufrufen. Das
151265
Hauptprogramm (Rufer oder Caller) stoppt, wartet auf den Abschluss des
152-
aufgerufenen Programms und setzt seine Bearbeitung erst dann fort. Das
266+
aufgerufenen Programms und setzt seine Bearbeitung erst dann fort.
267+
268+
Das
153269
blockierende Verhalten des Rufers generiert aber einen entscheidenden Nachteil -
154270
eine fehlende Reaktionsfähigkeit für die Zeit, in der die aufgerufene Methode
155271
zum Beispiel eine Netzwerkverbindung aufbaut, Daten speichert oder Berechnungen
@@ -173,7 +289,7 @@ zu finden.
173289

174290
Eine Lösung für diesen Ansatz könnten Threads bieten.
175291

176-
```csharp AsynchonousBehaviour
292+
```csharp Program.cs
177293
using System;
178294
using System.Threading;
179295

@@ -185,6 +301,8 @@ class Program {
185301
Console.WriteLine("Thread {0} started!", Thread.CurrentThread.ManagedThreadId);
186302
// doing some fancy things here
187303
int delay = rnd.Next(200, 500);
304+
// int delay = Random.Shared.Next(200, 500);
305+
//static ThreadLocal<Random> rnd = new ThreadLocal<Random>(() => new Random());
188306
Thread.Sleep(delay); // arbitrary duration
189307
Result[(int)index]= delay;
190308
Console.WriteLine("\nThread {0} says Hello", Thread.CurrentThread.ManagedThreadId);
@@ -213,7 +331,18 @@ class Program {
213331
}
214332
}
215333
```
216-
@LIA.eval(`["main.cs"]`, `mcs main.cs`, `mono main.exe`)
334+
```-xml AsynchonousBehaviour.csproj
335+
<Project Sdk="Microsoft.NET.Sdk">
336+
<PropertyGroup>
337+
<OutputType>Exe</OutputType>
338+
<TargetFramework>net8.0</TargetFramework>
339+
</PropertyGroup>
340+
<ItemGroup>
341+
<PackageReference Include="MathNet.Symbolics" Version="0.24.0" />
342+
</ItemGroup>
343+
</Project>
344+
```
345+
@LIA.eval(`["Program.cs", "project.csproj"]`, `dotnet build -nologo`, `dotnet run -nologo`)
217346

218347
Welche Nachteile sehen Sie in dieser Lösung?
219348

@@ -286,15 +415,18 @@ C# stellt für die asynchrone Programmierung die neuen Typen `Task` und `Task<T
286415
Verfügung. Diese sind zentrale Komponenten von den
287416
aufgabenbasierten asynchronen Muster (TAP - Task based Asynchronous Pattern), die in .NET Framework 4 eingeführt wurden.
288417

289-
Unterschied zwischen Task und Thread:
418+
| Aspekt | `Thread` | `Task` |
419+
| ----------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
420+
| **Zweck** | Repräsentiert einen physischen Ausführungspfad (Thread of Execution). | Repräsentiert eine asynchrone, geplante Arbeitseinheit auf höherer Abstraktionsebene. |
421+
| **Erstellung** | Mit `new Thread()` explizit erstellt. | Mit `Task.Run()` oder `Task.Factory.StartNew()` gestartet, meist über Thread-Pool. |
422+
| **Verwaltung** | Muss manuell gestartet und verwaltet werden. | Wird vom .NET-Thread-Pool verwaltet. |
423+
| **Rückgabewert** | Kein direkter Rückgabewert. Ergebnisse müssen über gemeinsame Variablen oder Callbacks verarbeitet werden. | Kann ein Ergebnis mit `Task<TResult>` zurückgeben. |
424+
| **Stornierung** | Keine native Unterstützung. Muss manuell implementiert werden. | Unterstützt Abbruch über `CancellationToken`. |
425+
| **Async-Unterstützung** | Nicht für `async`/`await` geeignet. | Vollständig integrierbar mit `async`/`await`. |
426+
| **Ressourcenverbrauch** | Teurer, da jeder Thread eigene Ressourcen verwendet. | Ressourcenschonender durch Wiederverwendung im Thread-Pool. |
427+
| **Nebenläufigkeit** | Führt exakt einen Codepfad aus. | Kann beliebig viele Tasks gleichzeitig verwalten (abhängig von Systemressourcen). |
428+
| **Abstraktionsebene** | Niedrig – direkte Steuerung der Threads. | Höher – Fokus auf *was* getan werden soll, nicht *wie*. |
290429

291-
+ Die Klasse Thread wird zum Erstellen und Bearbeiten einer Thread-Instanz verwendet. Ein Task stellt eine asynchrone Operation dar und ist Teil der Task Parallel Library, einer Reihe von APIs zur asynchronen und parallelen Ausführung von Tasks.
292-
+ Der Task kann ein Ergebnis zurückgeben. Es gibt keinen direkten Mechanismus, um das Ergebnis von einem Thread zurückzugeben.
293-
+ Task unterstützt die Stornierung durch die Verwendung von Storno-Tokens, Thread hingegen nicht.
294-
+ Ein Task kann mehrere Prozesse gleichzeitig ablaufen lassen. Bei Threads kann immer nur eine Aufgabe gleichzeitig laufen.
295-
+ Mit den Schlüsselwörtern 'async' und 'await' können wir Asynchronous leicht implementieren.
296-
+ Ein neuer Thread() hat nichts mit dem Thread-Pool zu tun, während jeder Task durch den Thread-Pool verwaltet wird.
297-
+ Ein Task ist ein Konzept auf höherer Ebene als ein Thread.
298430

299431
### Task-Klasse
300432

@@ -365,7 +497,6 @@ public class Example
365497
Thread.CurrentThread.ManagedThreadId);
366498
};
367499

368-
// Create a task but do not start it.
369500
Task t1 = new Task(action, "alpha");
370501
t1.Start();
371502
Console.WriteLine("t1 has been launched. (Main Thread={0})",

code/24_Tasks/AsyncExampleII/Program.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
public class Program
66
{
7-
public static Task Main()
8-
{ Console.WriteLine("Beispiel mit Download");
9-
int n=await DownloadFileAsync();
7+
public static async Task Main()
8+
{
9+
Console.WriteLine("Beispiel mit Download");
10+
int n = await DownloadFileAsync();
1011
Console.WriteLine("Zurück in Main()");
1112
Console.WriteLine(n);
1213
Console.WriteLine("Download abgeschlossen!");
@@ -17,10 +18,9 @@ public static async Task<int> DownloadFileAsync()
1718
using (var httpClient = new HttpClient())
1819
{
1920
Console.WriteLine("Starte den Download...");
20-
var url = "https://github.com/TUBAF-IfI-LiaScript/VL_Softwareentwicklung/blob/master/24_Tasks.md";
21+
var url = "https://raw.githubusercontent.com/TUBAF-IfI-LiaScript/VL_Softwareentwicklung/master/24_Tasks.md";
2122
var response = await httpClient.GetAsync(url);
2223
var content = await response.Content.ReadAsStringAsync();
23-
//Console.WriteLine("Datei heruntergeladen: " + content);
2424
return content.Length;
2525
}
2626
}

0 commit comments

Comments
 (0)