Stöd för multitrådad körning och anslutningspool i e‑postklienter
E‑postklienter såsom ImapClient, Pop3Client, och SmtpClient kan användas i en multitrådad miljö. En klient kan hålla en eller flera anslutningar mot en server. För att hantera anslutningsuppsättningen i en klient används en anslutningspool. Antalet anslutningar som kan skapas och användas samtidigt begränsas av CredentialsByHostClient.MaxConnectionsPerServer egenskap. Denna egenskap kan sättas till 1 eller ett högre värde. Som standard är den lika med 10.
En kommandokö implementeras för varje anslutning för att stödja multitrådade operationer. Kommandon implementerar de enklaste operationerna som definieras i protokollet, såsom Noop, Authenticate, och så vidare. En användare kan starta utförandet av fler kommandon än det finns tillgängliga anslutningar, men de kommer endast att köras när klienten kan skapa en anslutning för operationen.
Hur e‑postklienter beter sig i en multitrådad miljö
E‑postklienter har följande beteende:
-
När
MaxConnectionsPerServer = 1, skapar klienten en anslutning och utför autentisering och auktorisation. Denna anslutning hålls i arbetstillstånd tills klienten avsätts. Alla operationer från olika trådar riktas till en kommandokö som placeras i huvudanslutningen. -
När
MaxConnectionsPerServer > 1, skapar klienten det nödvändiga antalet anslutningar och utför autentisering och auktorisation för varje anslutning. En anslutning reserveras som huvudanslutning. Denna anslutning hålls i arbetstillstånd tills klienten avsätts. Alla andra anslutningar skapas och avsätts vid behov. Det maximala antalet sådana anslutningar definieras avMaxConnectionsPerServeregendom. Till exempel, omMaxConnectionsPerServer = 2, då reserveras en anslutning som huvudanslutning, och en andra anslutning används som extra för operationer som körs i andra trådar. Enligt detta, omMaxConnectionsPerServer = 3, då reserveras den första anslutningen som huvudanslutning, och två andra anslutningar används som extra för operationer som körs i andra trådar. När en begäran om en anslutning kommer från en ny tråd och alla anslutningar redan är i bruk, väntar klienten tills antalet använda anslutningar minskar. Detta är en mycket viktig punkt som klargör varför korrekt avsättning av anslutningar är så viktigt.
Exempel på att använda e‑postklienter i en multitrådad miljö
En användare kan utföra operationer i olika trådar på flera sätt. De kan delas in i två typer.
Använda asynkrona (Begin/End)-metoder
En användare använder de asynkrona (Begin/End)-metoderna som definieras i klienten. I så fall startar e‑postklienten nya trådar efter behov. En uppgiftskö implementeras i klienten (förväxla inte med kommandokön i anslutningen). En uppgift kan köras om en anslutning är tillgänglig. När antalet använda anslutningar blir mindre än gränsvärdet, skapar klienten en ny anslutning, skapar en tråd för den aktuella uppgiften och kör den. Ett exempel på att använda asynkrona operationer:
// Create an imapclient with host, user and password
ImapClient client = new ImapClient();
client.Host = "domain.com";
client.Username = "username";
client.Password = "password";
client.SelectFolder("InBox");
ImapMessageInfoCollection messages = client.ListMessages();
IAsyncResult res1 = client.BeginFetchMessage(messages[0].UniqueId);
IAsyncResult res2 = client.BeginFetchMessage(messages[1].UniqueId);
MailMessage msg1 = client.EndFetchMessage(res1);
MailMessage msg2 = client.EndFetchMessage(res2);
Använda användarskapade trådar
En användare kan skapa trådar med objekt som Thread, ThreadPool, Task, eller andra objekt avsedda för detta ändamål. En användare kan också använda trådar skapade i tredjepartskod. I så fall har klienten två beteendemodeller.
a. Om användaren inte har tagit hand om att skapa extra anslutningar för operationer i tråden, kommer alla operationer för den tråden att skickas till huvudanslutningens kommandokö. Följande är ett exempel på operationer i en extra tråd utan att skapa en ny anslutning — alla transaktioner görs via huvudanslutningen:
List<MailMessage> List = new List<MailMessage>();
ThreadPool.QueueUserWorkItem(delegate(object o)
{
client.SelectFolder("folderName");
ImapMessageInfoCollection messageInfoCol = client.ListMessages();
foreach (ImapMessageInfo messageInfo in messageInfoCol)
{
List.Add(client.FetchMessage(messageInfo.UniqueId));
}
});
b. När användaren kör en metod för att skapa en ny anslutning för en extra tråd, blockeras den tråden tills kvotvärdet för nya anslutningar ändras så att en ny anslutning tillåts. Därefter skapas en ny anslutning. Denna anslutning sätts som standardanslutning för alla operationer i den tråden. Efter att alla operationer i tråden är slutförda måste anslutningen avsättas. För att skapa nya anslutningar, använd CredentialsByHostClient.CreateConnection metoden. Denna metod returnerar ett objekt som implementerar IDisposable gränssnittet. För att släppa anslutningen, Dispose metod måste anropas. Skapande och avsättning av en anslutning måste utföras i den tråd där e‑postoperationerna utförs. Ett försök att skapa en ny anslutning i den tråd där e‑postklienten skapades leder till ett fel, eftersom den tråden inte kan användas för att skapa en ny anslutning för tillfället. Att skapa en ny anslutning är också inte möjligt när MaxConnectionsPerServer = 1. Ett kodexempel på att skapa en ny anslutning i en extra tråd:
List<MailMessage> List1 = new List<MailMessage>();
ThreadPool.QueueUserWorkItem(delegate(object o)
{
using (IDisposable connection = client.CreateConnection())
{
client.SelectFolder("FolderName");
ImapMessageInfoCollection messageInfoCol = client.ListMessages();
foreach (ImapMessageInfo messageInfo in messageInfoCol)
List1.Add(client.FetchMessage(messageInfo.UniqueId));
}
});
Anslutningspool
Från och med Aspose.Email 19.3 har anslutningspoolen omstrukturerats. Den EmailClient klassen introducerades, vilket så småningom ersatte CredentialsByHostClient klass. Den EmailClient klass tillhandahåller en ConnectionAsgmtMode egenskap som definierar läget för anslutningsallokering i en flertrådad miljö. EmailClient.ConnectionAsgmtMode sätts med ConnectionAsgmtType uppräkning.
Anslutningstyper
Det finns tre anslutningstyper:
- Huvudanslutningen. Detta är anslutningen som skapas och avsätts tillsammans med e‑postklienten. Den kan inte skapas eller avsättas manuellt.
- Standardanslutning. En användare kan skapa standardanslutningar för trådar med CreateConnection metoden. Om en standardanslutning finns, kommer alla metoder i e‑postklienten som körs i en tråd implicit att använda den anslutningen. Endast en standardanslutning kan existera per tråd. Den kan skapas manuellt eller automatiskt, beroende på
EmailClient.ConnectionAsgmtModeegenskap. Dessa anslutningar kan skapas manuellt medEmailClient.CreateConnection(createAsDefaultConnection = true)metoden. Om en standardanslutning inte används (beroende på anslutningstilldelningsläget) används huvudanslutningen implicit istället. - Oberoende anslutningar. Detta är anslutningar som inte är länkade till trådar. De kan skapas manuellt och måste användas explicit som en metodparameter. Dessa anslutningar kan skapas manuellt med
EmailClient.CreateConnection()metod eller denEmailClient.CreateConnection(createAsDefaultConnection = false)metod.
Anslutningsallokeringstyper
För att konfigurera EmailClient.ConnectionAsgmtMode egenskap, den ConnectionAsgmtType enumerationen används. Tilldelningstyperna den tillhandahåller listas nedan.
-
ConnectionAsgmtType.UseMainOrDefault Detta läge används som standard i e‑postklienter. E‑postklienten använder huvudanslutningen för alla operationer från flera trådar om en standardanslutning inte har skapats, eller om en anslutning inte har skickats som metodparameter explicit. Huvudanslutningen skapas samtidigt som e‑postklienten. Användaren kan skapa standardanslutningar för trådar med
CreateConnectionmetod. Om en standardanslutning för en tråd har skapats används den implicit för alla metoder i e‑postklienten som anropas i den tråden. Om en standardanslutning för en tråd inte har skapats används huvudanslutningen för alla metoder som anropas i den tråden. Användaren kan också skapa anslutningar som inte är länkade till trådar (inte standardanslutningar) medCreateConnectionmetod. För att använda andra anslutningar (varken huvud eller standard) måste användaren skicka anslutningen explicit som en parameter till metoden. Användaren kan dessutom skapa ett obegränsat antal anslutningar. Endast en standardanslutning kan existera per tråd. Observera att standardanslutningar fungerar korrekt om användaren använderThreadobjekt för multitaskingprogrammering. Om användaren använder en anslutningspool ellerTaskobjekt för multitasking, detta läge kan leda till felaktigt beteende. För att undvika detta problem måste användaren manuellt avsätta standardanslutningen (om den används) i slutet av kodexekveringen. -
ConnectionAsgmtType.UseMain E‑postklienten använder huvudanslutningen för alla operationer från flera trådar. Huvudanslutningen skapas samtidigt som e‑postklienten. Användaren kan inte skapa standardanslutningar, men kan skapa anslutningar som inte är länkade till trådar med
CreateConnectionmetod. För att använda andra anslutningar måste användaren skicka dem explicit som en metodparameter. -
ConnectionAsgmtType.UseDefault E‑postklienten använder endast standardanslutningar implicit för alla operationer från flera trådar. Huvudanslutningen används inte i detta läge. Om en standardanslutning inte har skapats för en tråd (vid första anropet av en e‑postklientmetod) skapar e‑postklienten en standardanslutning implicit för tråden innan den första operationen utförs. Användaren kan inte skapa standardanslutningar för trådar med
CreateConnectionmetod eftersom de skapas automatiskt. Användaren kan också skapa anslutningar som inte är länkade till trådar medCreateConnectionmetod. För att använda andra anslutningar måste användaren skicka dem explicit som en metodparameter. Användaren kan dessutom skapa ett obegränsat antal anslutningar. Endast en standardanslutning kan användas per tråd. Observera att standardanslutningar fungerar korrekt om användaren använderThreadobjekt för multitaskingprogrammering. Om användaren använder en anslutningspool ellerTaskobjekt för multitasking, detta läge kan leda till felaktigt beteende. För att undvika detta problem måste användaren manuellt avsätta standardanslutningen i slutet av kodexekveringen.
Rekommendationer
Om användaren skickar alla kommandon till huvudanslutningen kan en situation uppstå där kommandon från olika trådar blandas. Användaren bör förstå vilka kommandon som är beroende av sin sekvens och vidta åtgärder för att synkronisera sådana kommandon. Det är också nödvändigt att överväga möjligheten att köra kommandon i olika sessioner (IMAP/POP3). De mest tidskrävande operationerna är FetchMessage, AppendMessage, och Send. Det är troligen meningsfullt att utföra dessa operationer med en ny tråd och en ny anslutning. Snabba operationer såsom Delete ger mening att utföra med huvudanslutningen. Observera att initieringen av en ny anslutning är en ganska tidskrävande operation.