Podpora vícevláknového zpracování v e‑mailových klientech
Poštovní klienti jako ImapClient a Pop3Client umožňují uživatelům používat je v prostředí vícevláknového zpracování. Poštovní klienti umožňují mít jedno nebo více připojení k serveru. Pro správu sady připojení uvnitř klientů se používá pool připojení. Počet připojení, která mohou být vytvořena a používána současně, je omezen vlastností CredentialsByHostClient.MaxConnectionsPerServer. Tato vlastnost může být nastavena na 1 nebo vyšší hodnotu. Ve výchozím nastavení je tato hodnota 10. Pro podporu vícevláknových operací byl implementován fronta příkazů pro připojení. Příkazy implementují nejjednodušší operace definované v protokolu, jako Noop, Authenticate a podobně. Uživatel může spustit více příkazů, než je dostupných připojení. Příkazy však budou provedeny až tehdy, když klient bude schopen vytvořit připojení pro operaci.
Metody používání poštovních klientů ve vícevláknovém prostředí
E‑mailoví klienti mají následující chování:
1. V případě, že MaxConnectionsPerServer = 1, klient vytvoří 1 spojení, provede autentizaci a autorizaci. Toto spojení zůstává v pracovním stavu až do okamžiku, kdy je klient zlikvidován. Všechny operace z různých vláken jsou směrovány do jedné fronty příkazů umístěné v hlavním spojení.
2. V případě, že MaxConnectionsPerServer > 1, klient vytvoří požadovaný počet spojení, provede autentizaci a autorizaci pro každé spojení. Jedno spojení je rezervováno jako hlavní spojení. Toto spojení zůstává v pracovním stavu až do okamžiku, kdy je klient zlikvidován. Všechna ostatní spojení jsou vytvářena a rušena dle potřeby. Maximální počet takových spojení je definován vlastností MaxConnectionsPerServer, tj. například pokud je MaxConnectionsPerServer = 2, jedno je rezervováno jako hlavní spojení a druhé spojení slouží jako doplňkové pro operace prováděné v jiných vláknech. Podobně pokud je MaxConnectionsPerServer = 3, první spojení je hlavní a dvě další jsou použita jako doplňková pro operace ve vláknech. V případě, že přijde další požadavek na spojení z nového vlákna a všechna spojení jsou již využita, klient čeká, dokud se počet použitých spojení nesníží. Tento okamžik je velmi důležitý, protože vysvětluje, proč je správné uvolňování spojení tak podstatné.
Příklady
Uživatel může provádět operace v různých vláknech několika způsoby. Daří se je rozdělit do dvou typů:
1. Uživatel používá asynchronní metody (Begin/End) definované v klientovi. V tomto případě e‑mailový klient spouští nová vlákna podle potřeby. V klientovi je implementována fronta úkolů (prosím, nepleťte si ji s frontou příkazů ve spojení). Úkol může být proveden, pokud je k dispozici spojení. Jakmile počet použitých spojení klesne pod limitní hodnotu, klient vytvoří nové spojení, vytvoří vlákno pro aktuální úkol a úkol vykoná. Příklad použití asynchronních operací:
2. Uživatel může vytvářet vlákna pomocí objektů jako Thread, ThreadPool, Task nebo jiných určených objektů. Také může používat vlákna vytvořená v kódu třetích stran. V tomto případě má klient dva modely chování
a. Pokud uživatel nevytvořil další spojení pro operace ve vláknu, všechny operace tohoto vlákna budou odeslány do fronty příkazů hlavního spojení. Příklad operací v dalším vláknu bez vytvoření nového spojení, všechny transakce probíhají přes hlavní spojení:
b. Když uživatel spustí metodu pro vytvoření nového spojení pro další vlákno, je toto vlákno blokováno, dokud se neupraví kvóta pro nová spojení, aby bylo nové spojení povoleno. Pak je nové spojení vytvořeno. Toto spojení je nastaveno jako výchozí spojení pro všechny operace v tomto vlákně. Po dokončení všech operací v tomto vlákně musí být spojení uvolněno. Pro vytvoření nových spojení použijte metodu CredentialsByHostClient.CreateConnection. Tato metoda vrací objekt, který implementuje rozhraní IDisposable. Pro uvolnění spojení je třeba zavolat metodu Dispose. Vytváření a uvolňování spojení musí probíhat uvnitř vlákna, ve kterém se provádějí e‑mailové operace. Pokus o vytvoření nového spojení ve vlákně, ve kterém byl vytvořen e‑mailový klient, vede k chybě, protože toto vlákno v tuto chvíli nemůže být použito pro vytvoření nového spojení. Vytvoření nového spojení také není možné, když je MaxConnectionsPerServer = 1. Příklad kódu pro vytvoření nového spojení v dalším vlákně:
Doporučení
Stojí za zmínku, že pokud uživatel odesílá všechny příkazy přes hlavní spojení, může dojít k zamíchání příkazů z různých vláken. Uživatel by měl rozumět, které příkazy jsou závislé na svém pořadí, a přijmout opatření k synchronizaci takových příkazů. Je také nutné zvážit možnost vykonávání příkazů v různých relacích (IMAP/POP3). Nejsložitější operace, jako FetchMessage, AppendMessage a Send, mají pravděpodobně smysl provádět v novém vlákně a s novým spojením. Naopak rychlé operace jako Delete je vhodné provádět přes hlavní spojení. Upozorňujeme, že inicializace nového spojení je sama o sobě časově náročná operace.