Wie führe ich einen Task in einem neuen Thread aus und kehre sofort zum Aufrufer zurück?

8

In den letzten paar Monaten habe ich über async-awa in C # gelesen und wie man es richtig benutzt.

Für den Zweck einer Laborübung baue ich einen kleinen Tcp-Server, der Clients dienen soll, die sich damit verbinden. Das Programm ist eine Konsolenanwendung.

Ich verwende eine while-Schleife, um auf solche Verbindungen zu warten:

%Vor%

Also, bis jetzt wurde die Methode ProcessClientAsync, die ich gemacht habe, als async void markiert und ich würde es einfach ProcessClientAsync (client) nennen und der Aufruf würde sofort zum Aufrufer zurückkehren. Jedoch habe ich im Internet gelesen, dass es eine schlechte Entscheidung ist, es zu benutzen, es sei denn, es ist für eine Veranstaltung. Also habe ich die Definition in async Task geändert.

Ok, aber ohne zu warten, erhalte ich eine Warnung in Visual Studio: "Da dieser Aufruf nicht erwartet wird, wird die aktuelle Methode weiter ausgeführt, bevor der Aufruf abgeschlossen ist."

Und sobald ich ProcessClientAsync (Client) abgewartet habe, funktioniert der Code nicht. Ich kann nur einen Client verbinden, und dann "wartet" der Aufrufer auf die Rückgabe von ProcessClientAsync. Diese Methode hat jedoch eine Endlosschleife und wird nicht zurückkehren, aber ich brauche die while-Schleife, um mit der Verarbeitung des nächsten Clients fortzufahren.

Googeln Ich bin auf diesen Thread gekommen: So rufen Sie eine Async-Methode sicher auf C # ohne warten

Ich denke, die Fragen sind ziemlich gleich, außer dass ich ProcessClientAsync abwarten möchte, dass es sofort zum Aufrufer zurückkehrt, was es nicht tut, weil ich den zweiten Client laufe, während der erste ist läuft noch, der zweite Client verbindet sich nicht.

Also habe ich das gemacht:

%Vor%

Aber da ProcessClientAsync eine Aufgabe zurückgeben muss, bin ich nicht sicher, ob das OK ist?

Das wäre eine Frage.

Der andere wäre: Wie kann ich eine asynchrone Task-Methode aufrufen, die für immer läuft und den Anruf sofort an den Aufrufer zurückgibt, damit die while-Schleife fortgesetzt werden kann und der tcp-Listener den nächsten Client weiterhin akzeptieren kann?

Danke.

Tut mir leid, wenn es eine Wiederholung ist oder unklar, was ich frage.

    
Marin 07.06.2015, 18:56
quelle

3 Antworten

10
  

Für den Zweck einer Laborübung baue ich einen kleinen Tcp-Server, der Clients dienen soll, die sich damit verbinden. Das Programm ist eine Konsolenanwendung.

Nun, die allererste Sache, die ich empfehlen würde, ist eine einfachere Übung zu versuchen. Ernsthaft, ein asynchroner TCP-Server ist eine der komplexesten Anwendungen, die Sie auswählen können. Die große Mehrheit der Entwickler, die async verwenden, arbeiten an Apps zwei Größenordnungen einfacher.

Versuchen Sie stattdessen, eine UI-App zu schreiben, die eine Datei von einer URL herunterlädt. Das ist ein realistischerer Ausgangspunkt für das Lernen von async .

  

Aber da ProcessClientAsync eine Aufgabe zurückgeben muss, bin ich nicht sicher, ob das OK ist?

Ich würde empfehlen, Task.Run anstelle von Task.Factory.StartNew zu verwenden. Task.Run kennt async Methoden, StartNew nicht.

Das geht jedoch davon aus, dass das Starten eines Threads die richtige Operation ist. Die meisten TCP / IP-Serveranwendungen sind nicht an die CPU gebunden. Daher stelle ich hier die Verwendung mehrerer Threads in Frage. Es ist durchaus möglich, einen vollständig asynchronen TCP / IP-Server zu verwenden, der nur den Thread-Pool für seine async -Methodenfortsetzungen verwendet.

  

Das andere wäre: Wie kann ich eine asynchrone Task-Methode aufrufen, die für immer ausgeführt wird und den Anruf sofort an den Anrufer zurückgibt, damit die while-Schleife fortgesetzt werden kann und der tcp-Listener den nächsten Client weiterhin annehmen kann?

Sie haben einfach nicht await the Task zurück:

%Vor%

Allerdings wird sich der Compiler hier beschweren, weil dieser Code mit ziemlicher Sicherheit falsch ist. Wenn Sie die zurückgegebene Aufgabe ignorieren, ignorieren Sie alle Ausnahmen von diesem Code.

Ein gängiges Muster in TCP / IP-Server-Apps besteht darin, für jeden verbundenen Client eine kleine Sammlung von Status zu verwalten. Das ist ein natürlicher Ort, um sowohl das Socket-Objekt selbst als auch die Task, die die Behandlung dieser Socket-Verbindung darstellt, zu platzieren:

%Vor%

Diese Client-Zustände werden dann in einer Liste / einem Verzeichnis gespeichert. Wie genau du das tust, liegt natürlich bei dir.

    
Stephen Cleary 07.06.2015, 20:10
quelle
1

Dies startet die Aufgabe und kehrt zum Aufrufer zurück und vermeidet die Compiler-Warnung:

%Vor%     
glenebob 07.06.2015 19:03
quelle
0

Wenn ich Ihr Problem richtig verstanden habe, sollte dieser Code helfen:

%Vor%     
Oleg 07.06.2015 19:29
quelle