Warum dauert dieser C# Task so lange?

Was ist beim Mischen von synchronen mit asynchronen Tasks in C# das Problem, sodass der folgende Code extrem lange zur Ausführung benbötigt?

var sema = new SemaphoreSlim(1);

var tasks = new List<Task>();

for (int i = 0; i < 20; i++)
{
    var t2 = Task.Run(async () =>
    {
        var sw = new Stopwatch();
        sw.Start();
        await sema.WaitAsync().ConfigureAwait(false);
        try
        {
            await Task.Delay(1).ConfigureAwait(false);
        }
        finally
        {
            sema.Release();
        }
        sw.Stop();
        Console.WriteLine($"sync {sw.Elapsed}");
    });

    var t1 = Task.Run(() =>
    {
        var sw = new Stopwatch();
        sw.Start();
        sema.Wait();
        try
        {
        }
        finally
        {
            sema.Release();
        }
        sw.Stop();
        Console.WriteLine($"async {sw.Elapsed}");
    });

    tasks.Add(t1);
    tasks.Add(t2);
}

await Task.WhenAll(tasks).ConfigureAwait(false);

Ausgabe: es dauert 16 Sekunden!!! Nur die erste Ausgabe ist schnell, der Rest nach 16 Sekunden.

sync 00:00:00.8306484
sync 00:00:16.8401071
... Rest

Nehme ich beide male synchrone Tasks, geht es wesentlich schneller:

var sema = new SemaphoreSlim(1);

var tasks = new List<Task>();

for (int i = 0; i < 20; i++)
{
    var t2 = Task.Run(async () =>
    {
        var sw = new Stopwatch();
        sw.Start();
        await sema.WaitAsync().ConfigureAwait(false);
        try
        {
            await Task.Delay(1).ConfigureAwait(false);
        }
        finally
        {
            sema.Release();
        }
        sw.Stop();
        Console.WriteLine($"sync {sw.Elapsed}");
    });

    var t1 = Task.Run(async () =>
    {
        var sw = new Stopwatch();
        sw.Start();
        await sema.WaitAsync().ConfigureAwait(false);
        try
        {
        }
        finally
        {
            sema.Release();
        }
        sw.Stop();
        Console.WriteLine($"async {sw.Elapsed}");
    });

    tasks.Add(t1);
    tasks.Add(t2);
}

await Task.WhenAll(tasks).ConfigureAwait(false);

Ausgabe: alles nach etwa 300ms fertig.

async 00:00:00.0180861
sync 00:00:00.3329542
...

Was passiert da im Hintergrund? Ich weiß, dass man snchrone mit asynchronen Tasks nicht mischen soll, aber die 16 Sekunden sind schon heftig und kommen fast einem Deadlock gleich. Was passiert nach 16 Sekunden, dass es dann plötzlich weitergeht ;-) ?

Programmieren, CSharp, Informatik
Wie verteilen sich Tasks auf Threads unter C#?

Ich möchte unter C# viele (bis zu 5000) TCP Verbindungen als Server handeln.

Da ich die ganze Applikation asynchron aufgebaut habe, möchte ich dies, wenn möglich, auch für den Server tun. Die klassische Implementierung, wo nach jedem "accept" ein eigener Thread geöffnet wird, halte ich angesichts der großen Zahl an Sockets nicht für sinnvoll.

Nun hätte ich es so gelöst:

In diesem Beispiel listene ich auf Ports 5000 und 5001 und kann hier beliebig viele Verbindungen annehmen.

public class TestProgram
{
	private static async Task HandleClient(TcpClient clt)
	{
		using NetworkStream ns = clt.GetStream();
		using StreamReader sr = new StreamReader(ns);
		while (true)
		{
			string msg = await sr.ReadLineAsync();
			Console.WriteLine($"Received in {System.Threading.Thread.CurrentThread.ManagedThreadId} :({msg.Length} bytes):\n{msg}");
		}
	}
	private static async Task AcceptConnections(int port)
	{
		TcpListener listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
		listener.Start();
		while(true)
		{
			var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
			Console.WriteLine($"Accepted connection for port {port}");
			var task = HandleClient(client);
		}
	}


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


		var task1=AcceptConnections(5000);
		var task2=AcceptConnections(5001);


		await Task.WhenAll(task1, task2).ConfigureAwait(false);
	}
}

Aufgefallen ist mir nun folgendes:

Die verschiedenen "Instanzen" von HandleClient laufen nicht immer im gleichen Thread, wie man anhand der Ausgabe erkennt:

Accepted connection for port 5000
Accepted connection for port 5000
Accepted connection for port 5001
Received new message in 5 :(17 bytes):
Port-5000 Message
Received new message in 7 :(18 bytes):
Port-5000 Message 
Received new message in 7 :(18 bytes):
Port-5000 Message 
Received new message in 7 :(20 bytes):
Port-5000 Message -2
Received new message in 7 :(18 bytes):
Port-5000 Message 
Received new message in 7 :(18 bytes):
Port-5001 Message 
Received new message in 8 :(17 bytes):
Port-5001 Message

Die Nachrichten "Port-5000 Message", "Port-5000 Message -2" und "Port-5001 Message" werden über verschiedene Sockets empfangen. Nach welchen Kriterien wählt C# die Threads aus, in denen diese Tasks laufen. Ich dachte eigentlich, dass alles immer im selben Thread läuft; es wird ja oft gesagt, dass async/await nicht auf Threads basiert. Scheinbar ist das aber nicht ganz der Fall.

https://stackoverflow.com/questions/37419572/if-async-await-doesnt-create-any-additional-threads-then-how-does-it-make-appl

Wie funktioniert das also? Ich hab das noch nicht ganz verstanden...

Gibt es überhaupt eine elegantere Möglichkeit, dies zu tun? Ich habe mit C# noch nicht viel Erfahrung.

Computer, Technik, Programmieren, C Sharp, dotNet, Technologie, Thread, Programmieren in C-Sharp, Spiele und Gaming
Wie kommen Mathematiker auf solche Ideen?

Ich habe mir heute diese Folge von Videos angesehen:

https://www.youtube.com/watch?v=iJ8pnCO0nTY

Es geht um die Anzahl der möglichen additiven Partitionen ganzer Zahlen: Euler hat gezeigt, dass diese Anzahl p(n) auf eine Rekursionformel

p(n ) = p(n-1) + p(n-2) - p(n-5) - p(n-7) + p(n-12) + ...

zurückgeführt werden kann.

In dieser Videoserie wird eine Beweisidee in groben Zügen aufgezeigt.

Der springende Punkt ist dabei ein Zwischenbeweis, nämlich dass die Anzahl der geraden Partitionen von n gleich ist der Anzahl der ungeraden Partionen von n, außer es handelt sich bei n um eine (verallgemeinerte) pentagonale Zahl. Hut ab!

Im letzten Video wird das Ergebnis benutzt, um die obige Behauptung zu zeigen.

Ich habe den gesamten heutigen Nachmittag und auch den Abend damit verbracht, das ganze im Sinne des Vortragenden (d.h. auf populärmathematischem Niveau) zu verstehen. Dabei musste ich mir einige Stellen dutzende Male ansehen, bis ich jeweils den Punkt verstanden hatte.

Nachdem die Kernaussage im letzten Video urplötzlich wie ein Blitz aus heiterem Himmel aus den vorbereitenden Überlegungen folgte, war ich ziemlich geflasht. Das war eines der interessantesten Dinge der letzten Wochen...

Ich frage mich nun, wie man auf Deratiges kommt: Hat Euler ähnliche Überlegungen angestellt, um dieses Ergebnis zu erhalten und diese Gedanken "bloß" in eine mathematische Form gegossen, oder war sein Zugang ein komplett anderer, der für mich als Laie gar nicht mehr verständlich wäre? Der aufgezeigte Weg erscheint für mich "relativ" plausibel, wenn er auch natürlich keinen Beweis darstellt.

Angenommen ich möchte, nachdem mir das als "Aufwärmübung" ziemlich Spaß gemacht hat, nun auch den echten Beweis verstehen: würde mir die hier gewonnene "Einsicht" weiterhelfen, oder ist diese bloß eine nette Spielerei, die mit Mathematik nichts zu tun hat?

Die Frage ist theoretisch - ich glaube nicht, dass ich die Zeit hätte, mich einem solchen Versuch zu widmen, aber es interessiert mich, ob Mathematiker plausible Ideen wie diese einfach entsprechend ausarbeiten oder aber grundsätzlich anders vorgehen. In Worten: Hat ein Genie wie Euler einfach (wie hier) begonnen, in einer interessanten Zahlenreihe nach Regelmäßigkeiten zu suchen, oder ging er da schon von irgendwelchen "höheren Erkenntnissen" aus, ohne sich dem Problem auf so primitive Art zu nähern, wie es hier der Fall ist?

Ich hoffe meine Frage ist zu später Stunde halbwegs rübergekommen.

Schule, Mathematik, Mathematiker, Partition, Beweis, Euler
Wie konnte man schon sehr früh recht detailliert über die Struktur komplexer organischer Moleküle Bescheid wissen?

Ich frage mich schon sehr lange, wie man in der Chemie schon sehr früh die Struktur der relevanten Biomoleküle herausfinden konnte. Jetzt will ich das endlich mal niederschreiben:

Ich nehme nur als Beispiel die Nukleotide. Diese sind bestehen ja aus

  • einer Pentose
  • einer Pyrin- oder Pyrimidin Base an 1'
  • einer Esterbindung an 5' mit daranhängender Phosphatgruppe

Es handelt sich daher um durchaus komplexe Moleküle.

Die Ribose selbst liegt schon in mehreren Formen vor:

Wie zum Teufel konnte man herausfinden, wie die Struktur dieser Moleküle aussieht?

Nachlesen in Büchern und einfach hinnehmen ist ja einfach...aber angenommen ich habe eine Zelle: In dieser habe ich einen Zellkern, der neben ein paar Strukturproteinen sehr viel DNA enthält. Man mag diese beiden grundlegend verschiedenen Komponenten irgendwie trennen, aber dann hat man irgendeine unbekannte "Substanz" im Reagenzglas von der man NICHTS weiß. Wie kam man auf die Idee, dass es sich bei dieser gerade um eine Form der Des-Oxy-Ribonukeinsäure handelt. Wie konnte man z.B. feststellen, dass DNA im Vergleich zur RNA ein fehlendes O gerade an der Position 2' hat? Dieses Faktum steht ja nirgends auf einer Etikette drauf ;-)

Noch dazu liegt DNA in der Zelle ja in einer höchst komplexen Form vor und es gibt nicht eine sondern mehrere Basen. Ich habe gehört, dass man diese durch Elektrophorese trennen kann. Schön, dann weiß ich aber immer noch nicht, was in den Banden enthalten ist. Erwin Chargaff konnte bekanntlich zeigen, dass die Verhältnisse von G:C und A:T immer 1:1 sind. Woher wusste er aber, dass es diese Basen überhaupt gibt?

Wieso wusste man, dass sich 3'-5'-Ketten bilden- es "könnten" sich ja auch 2'-5' Ketten bilden. Diese Erkenntnis lag schon einige Zeit vor Watson/Crick/Franklin vor, diese zeigten erst die Doppelhelix.

Für mich als Laie ist es unvorstellbar und schon fast ein Wunder, wie man schon erstaunlich früh zu all diesen Erkenntnissen kommen konnte. Soweit ich weiß, lag die Röntgenstrukturanalyse damals noch in den Kinderschuhen und die Erkenntnisse von Watson/Crick/Franklin waren erst spät (1953). Es muss also andere strukturanalytische Verfahren gegeben haben, von denen ich scheinbar nichts weiß.

Kann mir ein Chemiker erklären, wie das funktioniert und wo man das fachlich nachlesen/lernen kann?

Ich hoffe es ist rübergekommen, worum es mir geht und habe nicht zu sehr ausgeschweift - es ist eine Frage, die mich schon seit langem außerordentlich berührt!

Wie konnte man schon sehr früh recht detailliert über die Struktur komplexer organischer Moleküle Bescheid wissen?
Schule, Chemie, Wissenschaft, Biochemie, DNA, Molekularbiologie, organische Chemie, RNA