การสนับสนุนหลายเธรดและพูลการเชื่อมต่อในไคลเอนต์เมล
ไคลเอนต์เมลเช่น ImapClient, Pop3Client, และ SmtpClient สามารถใช้ในสภาพแวดล้อมหลายเธรด ไคลเอนต์สามารถเก็บการเชื่อมต่อหนึ่งหรือหลายการเชื่อมต่อกับเซิร์ฟเวอร์ เพื่อจัดการชุดการเชื่อมต่อภายในไคลเอนต์ จะใช้ พูลการเชื่อมต่อ จำนวนการเชื่อมต่อที่สามารถสร้างและใช้พร้อมกันถูกจำกัดโดย CredentialsByHostClient.MaxConnectionsPerServer คุณสมบัติ การตั้งค่านี้อาจเป็น 1 หรือค่าที่มากกว่า โดยค่าเริ่มต้นเท่ากับ 10.
คิวคำสั่งถูกดำเนินการสำหรับแต่ละการเชื่อมต่อเพื่อสนับสนุนการทำงานหลายเธรด คำสั่งจะดำเนินการตามการดำเนินการพื้นฐานที่กำหนดในโปรโตคอล เช่น Noop, Authenticate, เป็นต้น ผู้ใช้อาจเริ่มการดำเนินการของคำสั่งมากกว่าจำนวนการเชื่อมต่อที่มีอยู่ แต่จะดำเนินการเมื่อไคลเอนต์สามารถสร้างการเชื่อมต่อสำหรับการดำเนินการนั้นได้.
วิธีที่ไคลเอนต์เมลทำงานในสภาพแวดล้อมหลายเธรด
ไคลเอนต์อีเมลมีพฤติกรรมต่อไปนี้:
-
เมื่อ
MaxConnectionsPerServer = 1, ไคลเอนต์จะสร้างการเชื่อมต่อหนึ่งและทำการรับรองความถูกต้องและการอนุญาต การเชื่อมต่อนี้จะอยู่ในสภาวะทำงานจนกว่าไคลเอนต์จะถูกกำจัด การดำเนินการทั้งหมดจากเธรดต่าง ๆ จะถูกส่งไปยังคิวคำสั่งเดียวที่วางไว้ในการเชื่อมต่อหลัก. -
เมื่อ
MaxConnectionsPerServer > 1, ไคลเอนต์จะสร้างจำนวนการเชื่อมต่อที่ต้องการและทำการรับรองความถูกต้องและการอนุญาตสำหรับทุกการเชื่อมต่อ การเชื่อมต่อหนึ่งจะถูกสงวนเป็นการเชื่อมต่อหลัก การเชื่อมต่อนี้จะอยู่ในสภาวะทำงานจนกว่าไคลเอนต์จะถูกกำจัด การเชื่อมต่ออื่น ๆ จะถูกสร้างและกำจัดตามความต้องการ จำนวนสูงสุดของการเชื่อมต่อดังกล่าวกำหนดโดยMaxConnectionsPerServerคุณสมบัติ. ตัวอย่างเช่น หากMaxConnectionsPerServer = 2, จากนั้นการเชื่อมต่อหนึ่งจะถูกสงวนเป็นการเชื่อมต่อหลัก และการเชื่อมต่อที่สองจะถูกใช้เป็นการเชื่อมต่อเพิ่มเติมสำหรับการดำเนินการในเธรดอื่น ดังนั้น ถ้าMaxConnectionsPerServer = 3, จากนั้นการเชื่อมต่อแรกจะถูกสงวนเป็นการเชื่อมต่อหลัก และสองการเชื่อมต่ออื่นจะถูกใช้เป็นการเชื่อมต่อเพิ่มเติมสำหรับการดำเนินการที่ทำในเธรดอื่น เมื่อต้องการการเชื่อมต่อจากเธรดใหม่และการเชื่อมต่อทั้งหมดถูกใช้งานอยู่ ไคลเอนต์จะรอจนจำนวนการใช้การเชื่อมต่อลดลง นี้เป็นจุดสำคัญที่ทำให้เข้าใจว่าการกำจัดการเชื่อมต่ออย่างถูกต้องสำคัญขนาดไหน.
ตัวอย่างการใช้ไคลเอนต์เมลในสภาพแวดล้อมแบบหลายเธรด
ผู้ใช้อาจดำเนินการในเธรดต่าง ๆ ได้หลายวิธี สามารถแบ่งเป็นสองประเภท.
การใช้เมธอดอะซิงโครนัส (Begin/End)
ผู้ใช้ใช้เมธอดแบบอะซิงโครนัส (Begin/End) ที่กำหนดในไคลเอนต์ ในกรณีนี้ ไคลเอนต์เมลจะเปิดเธรดใหม่เมื่อจำเป็น คิวงานถูกดำเนินการในไคลเอนต์ (อย่ากับระบบคิวคำสั่งในพลูลการเชื่อมต่อ) งานอาจถูกดำเนินการหากมีการเชื่อมต่อที่พร้อมใช้งาน เมื่อจำนวนการใช้การเชื่อมต่อมากกว่าค่าที่กำหนด ไคลเอนต์จะสร้างการเชื่อมต่อใหม่ สร้างเธรดสำหรับงานนั้นและดำเนินการ งานตัวอย่างของการใช้การดำเนินการแบบอะซิงโครนัส:
// 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);
การใช้เธรดที่สร้างโดยผู้ใช้
ผู้ใช้อาจสร้างเธรดโดยใช้ออบเจ็กต์เช่น Thread, ThreadPool, Task, หรือออบเจ็กต์อื่นใดที่ตั้งใจสำหรับวัตถุประสงค์นี้ ผู้ใช้อาจใช้เธรดที่สร้างโดยโค้ดของบุคคลที่สาม ในกรณีนี้ ไคลเอ็นต์มีสองรูปแบบพฤติกรรม.
a. หากผู้ใช้ไม่ได้จัดการสร้างการเชื่อมต่อเพิ่มเติมสำหรับการดำเนินการในเธรดทั้งหมด การดำเนินการทั้งหมดสำหรับเธรดนี้จะถูกส่งไปยังคิวคำสั่งของการเชื่อมต่อหลัก ตัวอย่างต่อไปนี้เป็นการดำเนินการในเธรดเพิ่มเติมโดยไม่ได้สร้างการเชื่อมต่อใหม่ — ทุกธุรกรรมถูกทำผ่านการเชื่อมต่อหลัก:
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. เมื่อผู้ใช้เรียกเมธอดเพื่อสร้างการเชื่อมต่อใหม่สำหรับเธรดเพิ่มเติม เธรดนั้นจะถูกบล็อกจนกว่าจะมีการเปลี่ยนค่าความจำกัดของการเชื่อมต่อใหม่ให้อนุญาตการเชื่อมต่อใหม่ จากนั้นการเชื่อมต่อใหม่จะถูกสร้าง การเชื่อมต่อนี้จะถูกตั้งเป็นการเชื่อมต่อเริ่มต้นสำหรับทุกการดำเนินการในเธรดนี้ หลังจากการดำเนินการทั้งหมดเสร็จสิ้น การเชื่อมต่อต้องถูกกำจัด เพื่อสร้างการเชื่อมต่อใหม่ ใช้ CredentialsByHostClient.CreateConnection เมธอด. เมธอดนี้ส่งกลับออบเจ็กต์ที่ทำงานตาม IDisposable อินเทอร์เฟซ. เพื่อปล่อยการเชื่อมต่อ, the Dispose เมธอดต้องถูกเรียกใช้ การสร้างและการกำจัดการเชื่อมต่อต้องดำเนินการภายในเธรดที่ทำการดำเนินการเมล การพยายามสร้างการเชื่อมต่อใหม่ในเธรดที่สร้างไคลเอนต์เมลจะทำให้เกิดข้อผิดพลาด เนื่องจากเธรดนี้ไม่สามารถใช้สร้างการเชื่อมต่อใหม่ได้ในขณะนั้น การสร้างการเชื่อมต่อใหม่ยังเป็นไปไม่ได้เมื่อ MaxConnectionsPerServer = 1. ตัวอย่างโค้ดในการสร้างการเชื่อมต่อใหม่ในเธรดเพิ่มเติม:
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));
}
});
พูลการเชื่อมต่อ
ตั้งแต่ Aspose.Email 19.3, พูลการเชื่อมต่อได้รับการปรับโครงสร้างใหม่. The EmailClient คลาสถูกแนะนำ ซึ่งในที่สุดจะมาแทนที่ CredentialsByHostClient คลาส. เมธอด EmailClient คลาสให้ ConnectionAsgmtMode คุณสมบัติที่กำหนดโหมดการจัดสรรการเชื่อมต่อในสภาพแวดล้อมหลายเธรด EmailClient.ConnectionAsgmtMode ถูกตั้งค่าด้วย ConnectionAsgmtType enumeration.
ประเภทการเชื่อมต่อ
มีประเภทการเชื่อมต่อสามประเภท:
- การเชื่อมต่อหลัก นี่คือการเชื่อมต่อที่สร้างและกำจัดพร้อมกับไคลเอนต์เมล ไม่สามารถสร้างหรือกำจัดด้วยตนเองได้.
- การเชื่อมต่อเริ่มต้น ผู้ใช้สามารถสร้างการเชื่อมต่อเริ่มต้นสำหรับเธรดด้วย CreateConnection เมธอด หากมีการเชื่อมต่อเริ่มต้นอยู่ ทุกเมธอดของไคลเอนต์เมลที่ทำงานในเธรดนั้นจะใช้การเชื่อมต่อนี้โดยอัตโนมัติ การเชื่อมต่อเริ่มต้นสามารถมีได้เพียงหนึ่งต่อเธรด สามารถสร้างด้วยตนเองหรืออัตโนมัติ ขึ้นกับ
EmailClient.ConnectionAsgmtModeคุณสมบัติ การเชื่อมต่อเหล่านี้สามารถสร้างด้วยEmailClient.CreateConnection(createAsDefaultConnection = true)เมธอด หากไม่ได้ใช้การเชื่อมต่อเริ่มต้น (ขึ้นกับโหมดการจัดสรรการเชื่อมต่อ) การเชื่อมต่อหลักจะถูกใช้โดยอัตโนมัติแทน. - การเชื่อมต่ออิสระ ซึ่งเป็นการเชื่อมต่อที่ไม่ได้เชื่อมโยงกับเธรดใดๆ สามารถสร้างด้วยตนเองและต้องใช้เป็นพารามิเตอร์ของเมธอดอย่างชัดเจน การเชื่อมต่อเหล่านี้สามารถสร้างด้วย
EmailClient.CreateConnection()เมธอดหรือ theEmailClient.CreateConnection(createAsDefaultConnection = false)เมธอด.
ประเภทการจัดสรรการเชื่อมต่อ
เพื่อกำหนดค่า EmailClient.ConnectionAsgmtMode คุณสมบัติ, the ConnectionAsgmtType การนับประเภทนี้ถูกใช้ ประเภทการจัดสรรที่ให้มามีดังต่อไปนี้.
-
ConnectionAsgmtType.UseMainOrDefault โหมดนี้เป็นค่าเริ่มต้นในไคลเอนต์เมล ไคลเอนต์เมลใช้การเชื่อมต่อหลักสำหรับทุกการดำเนินการจากหลายเธรด หากไม่มีการสร้างการเชื่อมต่อเริ่มต้น หรือหากไม่ได้ส่งผ่านการเชื่อมต่อเป็นพารามิเตอร์ของเมธอดอย่างชัดเจน การเชื่อมต่อหลักจะถูกสร้างพร้อมกับไคลเอนต์เมล ผู้ใช้สามารถสร้างการเชื่อมต่อเริ่มต้นสำหรับเธรดด้วย
CreateConnectionเมธอด หากการเชื่อมต่อเริ่มต้นสำหรับเธรดถูกสร้าง มันจะถูกใช้โดยอัตโนมัติสำหรับเมธอดทั้งหมดของไคลเอนต์เมลที่เรียกในเธรดนั้น หากไม่มีการเชื่อมต่อเริ่มต้นสำหรับเธรด การเชื่อมต่อหลักจะถูกใช้สำหรับเมธอดทั้งหมดที่เรียกในเธรดนั้น ผู้ใช้ยังสามารถสร้างการเชื่อมต่อที่ไม่ได้เชื่อมโยงกับเธรด (ไม่ใช่การเชื่อมต่อเริ่มต้น) ด้วยCreateConnectionเมธอด เพื่อใช้การเชื่อมต่ออื่น (ไม่ใช่หลักและไม่ใช่เริ่มต้น) ผู้ใช้ต้องส่งผ่านการเชื่อมต่ออย่างชัดเจนเป็นพารามิเตอร์ของเมธอด ผู้ใช้ยังสามารถสร้างการเชื่อมต่อได้หลายจำนวน การเชื่อมต่อเริ่มต้นสามารถมีได้เพียงหนึ่งต่อเธรด โปรดทราบว่าการเชื่อมต่อเริ่มต้นทำงานอย่างถูกต้องหากผู้ใช้ใช้Threadออบเจ็กต์สำหรับการเขียนโปรแกรมแบบหลายงาน หากผู้ใช้ใช้พูลการเชื่อมต่อหรือTaskออบเจ็กต์สำหรับการทำงานหลายงาน, โหมดนี้อาจทำให้พฤติกรรมไม่ถูกต้อง เพื่อหลีกเลี่ยงปัญหานี้ ผู้ใช้ต้องกำจัดการเชื่อมต่อเริ่มต้นด้วยตนเอง (หากใช้) เมื่อจบการทำงานของโค้ด. -
ConnectionAsgmtType.UseMain ไคลเอนต์เมลใช้การเชื่อมต่อหลักสำหรับทุกการดำเนินการจากหลายเธรด การเชื่อมต่อหลักถูกสร้างพร้อมกับไคลเอนต์เมล ผู้ใช้ไม่สามารถสร้างการเชื่อมต่อเริ่มต้นได้ แต่สามารถสร้างการเชื่อมต่อที่ไม่ได้เชื่อมโยงกับเธรดโดยใช้
CreateConnectionเมธอดนี้ เพื่อใช้การเชื่อมต่ออื่น ผู้ใช้ต้องส่งผ่านโดยชัดเจนเป็นพารามิเตอร์ของเมธอด. -
ConnectionAsgmtType.UseDefault ไคลเอนต์เมลใช้การเชื่อมต่อเริ่มต้นโดยอัต implicit สำหรับทุกการดำเนินการจากหลายเธรด การเชื่อมต่อหลักไม่ได้ใช้ในโหมดนี้ หากยังไม่มีการเชื่อมต่อเริ่มต้นสำหรับเธรด (เมื่อเรียกเมธอดของไคลเอนต์เมลเป็นครั้งแรก) ไคลเอนต์เมลจะสร้างการเชื่อมต่อเริ่มต้นโดยอัตโนมัติสำหรับเธรดก่อนที่การดำเนินการแรกจะถูกประมวลผล ผู้ใช้ไม่สามารถสร้างการเชื่อมต่อเริ่มต้นสำหรับเธรดด้วย
CreateConnectionเมธอดเนื่องจากมันถูกสร้างโดยอัตโนมัติ ผู้ใช้ยังสามารถสร้างการเชื่อมต่อที่ไม่ได้เชื่อมโยงกับเธรดโดยใช้CreateConnectionเมธอด. เพื่อใช้การเชื่อมต่ออื่น ๆ ผู้ใช้ต้องส่งผ่านโดยชัดเจนเป็นพารามิเตอร์ของเมธอด ผู้ใช้ยังสามารถสร้างการเชื่อมต่อได้หลายจำนวน การเชื่อมต่อเริ่มต้นสามารถใช้ได้เพียงหนึ่งต่อเธรด โปรดทราบว่าการเชื่อมต่อเริ่มต้นทำงานอย่างถูกต้องหากผู้ใช้ใช้Threadออบเจ็กต์สำหรับการเขียนโปรแกรมแบบหลายงาน หากผู้ใช้ใช้พูลการเชื่อมต่อหรือTaskออบเจ็กต์สำหรับการทำงานหลายงาน, โหมดนี้อาจทำให้พฤติกรรมไม่ถูกต้อง เพื่อหลีกเลี่ยงปัญหานี้ ผู้ใช้ต้องทำการกำจัดการเชื่อมต่อเริ่มต้นด้วยตนเองเมื่อจบการทำงานของโค้ด.
คำแนะนำ
หากผู้ใช้ส่งคำสั่งทั้งหมดไปยังการเชื่อมต่อหลัก, อาจเกิดสถานการณ์ที่คำสั่งจากเธรดต่าง ๆ ผสมกัน ผู้ใช้ควรเข้าใจว่าคำสั่งใดต้องพึ่งพาลำดับของมันและดำเนินการซิงโครไนซ์คำสั่งเหล่านั้น นอกจากนี้ยังต้องพิจารณาความเป็นไปได้ของการรันคำสั่งในเซสชันต่าง ๆ (IMAP/POP3) การดำเนินการที่ใช้เวลานานที่สุดคือ FetchMessage, AppendMessage, และ Send. คงจะเหมาะสมที่จะทำงานเหล่านี้ด้วยเธรดใหม่และการเชื่อมต่อใหม่ การดำเนินการที่รวดเร็วเช่น Delete เหมาะสมที่จะทำด้วยการเชื่อมต่อหลัก โปรดทราบว่าการเริ่มต้นการเชื่อมต่อใหม่เป็นการดำเนินการที่ใช้เวลานาน.