Поддръжка на многонитово програмиране в имейл клиенти
Пощенските клиенти като ImapClient и Pop3Client позволяват на потребителите да ги използват в многонитова среда. Пощенските клиенти могат да имат една или повече връзки със сървър. За управление на набор от връзки в клиентите се използва пул от връзки. Броят на връзките, които могат да се създадат и използват едновременно, е ограничен от свойството CredentialsByHostClient.MaxConnectionsPerServer. Това свойство може да се зададе със стойност 1 или по-голяма. По подразбиране това свойство е равно на 10. За връзката е внедрена опашка от команди, за да се поддържат многонитови операции. Командите реализират най-простите операции, дефинирани в протокола, като Noop, Authenticate и др. Потребителят може да стартира изпълнението на по-голям брой команди, отколкото има налични връзки. Но те ще се изпълнят само когато клиентът успее да създаде връзка за операцията.
Методи за използване на пощенски клиенти в многонитова среда
Имейл клиентите имат следното поведение:
1. При MaxConnectionsPerServer = 1 клиентът създава 1 връзка, извършва автентикация и упълномощаване. Тази връзка остава в работно състояние, докато клиентът не бъде освободен. Всички операции от различни нишки се насочват към една опашка от команди, поставена в главната връзка.
2. При MaxConnectionsPerServer > 1 клиентът създава необходимия брой връзки, извършва автентикация и упълномощаване за всяка връзка. Една връзка се запазва като главна връзка. Тази връзка остава в работно състояние, докато клиентът не бъде освободен. Всички останали връзки се създават и освобождават при нужда. Максималният брой такива връзки се определя от свойството MaxConnectionsPerServer, т.е. например ако MaxConnectionsPerServer = 2, една се запазва като главна връзка, а втората се използва като допълнителна за операции, изпълнявани в други нишки. По същия начин, ако MaxConnectionsPerServer = 3, първата връзка е главна, а две други се използват като допълнителни за операции в други нишки. Ако дойде нова заявка за връзка от нова нишка и всички връзки вече са заети, клиентът изчаква, докато броят на използваните връзки не се намали. Това е много важен момент, който обяснява защо правилното освобождаване на връзките е толкова важно.
Примери
Потребителят може да изпълнява операции в различни нишки по няколко начина. Те могат да се разделят на два типа:
1. Потребителят използва асинхронни (Begin/End) методи, определени в клиента. В този случай имейл клиентът създава нови нишки при необходимост. В клиента е реализирана опашка от задачи (моля, не се бъркайте с опашката от команди във връзката). Задачата може да се изпълни, ако връзката е налична. Когато броят на използваните връзки стане по-малък от лимита, клиентът създава нова връзка, създава нишка за текущата задача и я изпълнява. Пример за използване на асинхронни операции:
2. Потребителят може да създава нишки, използвайки обекти като Thread, ThreadPool, Task или други обекти за тази цел. Също така потребителят може да използва нишки, създадени в трети страни код. По време на това клиентът има два модела на поведение
a. Ако потребителят не е създал допълнителни връзки за операции в нишката, всички операции за тази нишка ще бъдат изпратени към опашката от команди към главната връзка. Пример за операции в допълнителна нишка без създаване на нова връзка, всички транзакции се извършват чрез главната връзка:
b. Когато потребителят извика метод за създаване на нова връзка за допълнителна нишка, тази нишка се блокира, докато стойността на квотата за нови връзки бъде променена, за да се позволи новата връзка. След това се създава нова връзка. Тази връзка се задава като връзка по подразбиране за всички операции в тази нишка. След като всички операции в нишката приключат, връзката трябва да бъде освободена. За създаване на нови връзки използвайте метода CredentialsByHostClient.CreateConnection. Този метод връща обект, който имплементира интерфейса IDisposable. За освобождаване на връзката трябва да се извика методът Dispose. Създаването и освобождаването на връзката трябва да се изпълнява в нишката, в която се изпълняват имейл операциите. Опит за създаване на нова връзка в нишката, в която е създаден имейл клиентът, води до грешка, тъй като тази нишка в момента не може да се използва за създаване на нова връзка. Също така създаването на нова връзка не е възможно, когато MaxConnectionsPerServer = 1. Примерен код за създаване на нова връзка в допълнителна нишка:
Препоръки
Струва си да се отбележи, че ако потребителят изпраща всички команди към главната връзка, може да възникне ситуация, при която команди от различни нишки се смесват. Потребителят трябва да разбира кои команди са зависими от реда им и да предприеме мерки за синхронизация на такива команди. Също така е необходимо да се вземе предвид възможността за изпълнение на команди в различни сесии (IMAP/POP3). Най-времеемките операции, като FetchMessage, AppendMessage и Send, вероятно имат смисъл да се изпълняват в нова нишка и нова връзка. Но бързите операции, като Delete, имат смисъл да се изпълняват с главната връзка. Моля, имайте предвид, че инициализирането на нова връзка е достатъчно времеемка операция.