Mehrthread‑Unterstützung in Mail‑Clients

Mail‑Clients wie ImapClient und Pop3Client ermöglichen die Verwendung in einer Multi‑Threading‑Umgebung. Mail‑Clients können eine oder mehrere Verbindungen zu einem Server besitzen. Zur Verwaltung einer Menge von Verbindungen innerhalb der Clients wird ein Connection‑Pool verwendet. Die Anzahl der gleichzeitig erstellbaren und nutzbaren Verbindungen ist durch die Eigenschaft CredentialsByHostClient.MaxConnectionsPerServer begrenzt. Diese Eigenschaft kann auf 1 oder einen höheren Wert gesetzt werden; standardmäßig ist sie 10. Für die Verbindung wurde eine Befehlswarteschlange implementiert, um Multi‑Threading‑Operationen zu unterstützen. Die Befehle implementieren einfachste im Protokoll definierte Vorgänge, wie Noop, Authenticate usw. Der Benutzer kann mehr Befehle starten, als verfügbare Verbindungen vorhanden sind. Die Befehle werden jedoch erst ausgeführt, wenn der Client eine Verbindung für die Operation herstellen kann.

Methoden zur Verwendung von Mail-Clients in einer Multi‑Threading‑Umgebung

E‑Mail‑Clients haben das folgende Verhalten:

1. Falls MaxConnectionsPerServer = 1, erstellt der Client 1 Verbindung, führt Authentifizierung und Autorisierung durch. Diese Verbindung bleibt im Arbeitszustand, bis der Client disposed wird. Alle Vorgänge aus verschiedenen Threads werden in einer Befehlswarteschlange der Hauptverbindung geleitet.

2. Falls MaxConnectionsPerServer > 1, erstellt der Client die benötigte Anzahl von Verbindungen, führt Authentifizierung und Autorisierung für jede Verbindung durch. Eine Verbindung wird als Hauptverbindung reserviert. Diese Verbindung bleibt im Arbeitszustand, bis der Client disposed wird. Alle anderen Verbindungen werden bei Bedarf erstellt und disposed. Die maximale Anzahl solcher Verbindungen wird durch die Eigenschaft MaxConnectionsPerServer definiert, d.h. zum Beispiel, wenn MaxConnectionsPerServer = 2, dann ist eine als Hauptverbindung reserviert und die zweite wird als zusätzliche für Vorgänge in anderen Threads verwendet. Entsprechend, wenn MaxConnectionsPerServer = 3, dann ist die erste Verbindung als Hauptverbindung reserviert und die beiden anderen Verbindungen werden als zusätzliche für Vorgänge in anderen Threads verwendet. Falls ein neuer Verbindungswunsch von einem neuen Thread kommt und alle Verbindungen bereits belegt sind, wartet der Client, bis die Anzahl der genutzten Verbindungen verringert wird. Dieser wichtige Punkt erklärt, warum das korrekte Freigeben von Verbindungen so wichtig ist.

Beispiele

Der Benutzer kann Vorgänge in verschiedenen Threads auf mehrere Arten ausführen. Sie lassen sich in zwei Typen unterteilen:

1. Der Benutzer verwendet asynchrone (Begin/End) Methoden, die im Client definiert sind. In diesem Fall startet der Mail‑Client bei Bedarf neue Threads. Im Client ist eine Aufgabenwarteschlange implementiert (bitte nicht mit der Befehlswarteschlange in der Verbindung verwechseln). Eine Aufgabe kann ausgeführt werden, wenn eine Verbindung verfügbar ist. Sobald die Anzahl der genutzten Verbindungen unter den Grenzwert fällt, erstellt der Client eine neue Verbindung, erzeugt einen Thread für die aktuelle Aufgabe und führt diese Aufgabe aus. Beispiel für die Verwendung asynchroner Vorgänge:

2. Der Benutzer kann Threads mit Objekten wie Thread, ThreadPool, Task oder anderen dafür vorgesehenen Objekten erstellen. Außerdem kann der Benutzer Threads aus Drittanbieter‑Code verwenden. Dabei hat der Client zwei Verhaltensmodelle

a. Wenn der Benutzer keine zusätzlichen Verbindungen für Vorgänge im Thread erstellt hat, werden alle Vorgänge dieses Threads an die Befehlswarteschlange der Hauptverbindung gesendet. Ein Beispiel für Vorgänge in einem zusätzlichen Thread ohne Erstellung einer neuen Verbindung, alle Transaktionen werden über die Hauptverbindung durchgeführt:

b. Wenn der Benutzer die Methode aufruft, um für einen zusätzlichen Thread eine neue Verbindung zu erstellen, wird dieser Thread blockiert, bis der Quotenwert für neue Verbindungen geändert wird, um eine neue Verbindung zu ermöglichen. Dann wird die neue Verbindung erstellt. Diese Verbindung wird als Standardverbindung für alle Vorgänge in diesem Thread festgelegt. Nachdem alle Vorgänge in diesem Thread abgeschlossen sind, muss die Verbindung freigegeben werden. Zum Erstellen neuer Verbindungen verwenden Sie die Methode CredentialsByHostClient.CreateConnection. Diese Methode gibt ein Objekt zurück, das das IDisposable‑Interface implementiert. Um die Verbindung freizugeben, muss die Dispose‑Methode aufgerufen werden. Erstellung und Freigabe der Verbindung müssen im Thread durchgeführt werden, in dem die Mail‑Operationen ausgeführt werden. Der Versuch, eine neue Verbindung im Thread zu erstellen, in dem der Mail‑Client erstellt wurde, führt zu einem Fehler, weil dieser Thread zu diesem Zeitpunkt nicht für das Erstellen einer neuen Verbindung verwendet werden kann. Außerdem ist das Erstellen einer neuen Verbindung nicht möglich, wenn MaxConnectionsPerServer = 1. Ein Codebeispiel zum Erstellen einer neuen Verbindung in einem zusätzlichen Thread:

Empfehlungen

Es ist zu beachten, dass wenn der Benutzer alle Befehle über die Hauptverbindung sendet, eine Situation entstehen kann, in der Befehle aus verschiedenen Threads vermischt werden. Der Benutzer sollte verstehen, welche Befehle von ihrer Reihenfolge abhängen, und Maßnahmen zur Synchronisation solcher Befehle ergreifen. Es ist ebenfalls nötig, die Möglichkeit der Ausführung von Befehlen in verschiedenen Sitzungen (IMAP/POP3) zu berücksichtigen. Die zeitintensivsten Operationen, wie FetchMessage, AppendMessage und Send, sollten wahrscheinlich in einem neuen Thread und einer neuen Verbindung durchgeführt werden. Schnellere Operationen wie Delete können jedoch mit der Hauptverbindung ausgeführt werden. Bitte beachten Sie, dass die Initialisierung einer neuen Verbindung bereits eine zeitintensive Operation ist.