C# 使用執行緒池佇列(學習筆記)
場景
- 當初客戶要求給自己的營業部和營業所推送郵件(收件人超1000個)
- 郵件正文是去下載報表WORD(檔案大小5M以上)資料檔案轉成HTML
- 三個附件檔案也是要去報表上下載EXCEL(檔案大小3M以上)
- 郵件要在10點之間推送完,但是這裡報表的資料是8點以後ETL才刷好(資料刷好的時間不準確)
解決方案
- 1000個郵箱用迴圈去跑肯定慢;就算1分鐘10封郵件也發不完;而且也沒有這麼高的效能
- 為了提高傳送郵件的效能不得不去使用C#執行緒程式設計;我在這裡使用了執行緒池這個東西,主要是因為執行緒池有佇列、可以設定執行緒池中有多個執行緒一起做任務、執行緒池可以更好得控制CPU資源自己回收
A.SQL
CREATE DATABASE [SendEmailTest]
USE [SendEmailTest]
GO
CREATE TABLE [dbo].[mailboxUser](
[ID] [int] IDENTITY(1,1) NOT NULL,
[subject] [nvarchar](120) NULL,
[mailBody] [nvarchar](255) NULL,
[toEmail] [nvarchar](100) NULL,
[toEmailBCC] [nvarchar](100) NULL,
[State] [nchar](10) NULL,
[Creater] [nvarchar](100) NULL,
[CreateTime] [datetime] NULL,
[Updater] [nvarchar](100) NULL,
[UpdateTime] [datetime] NULL,
CONSTRAINT [PK_mailboxUser] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
DECLARE @count INT,@i INT
SET @count=120
SET @i=1
WHILE @i<=@count
BEGIN
INSERT INTO [mailboxUser] VALUES
(
'今天又是有希望得一天;'+CAST(@i AS NVARCHAR),
'今天要把任務做完;'+CAST(@i AS NVARCHAR),
'yincongpeng2019@163.com',
'',
'1',
'abel',
GETDATE(),
null,
null
)
SET @i=@i+1
END
B.控制檯程式碼
class Program
{
private static string userEmail = ConfigHelper.GetConfigStr("userEmail"); //發件人郵箱
private static string userPswd = ConfigHelper.GetConfigStr("userPswd"); //郵箱帳號密碼
private static string mailServer = ConfigHelper.GetConfigStr("mailServer"); //郵件伺服器
private static string attachFilesPath = ConfigHelper.GetConfigStr("attachFilesPath"); //檔案地址
private static string ServerDataDB = ConfigHelper.GetConfigStr("ServerDataDB");
static void Main(string[] args)
{
Console.WriteLine("------------------------------------------------------------------------------1.程式開始");
Stopwatch watch = new Stopwatch();
watch.Start(); //開始監視
ThreadUseAndConstruction();
//StartSendMail(1,"test","郵件傳送測試", "yincongpeng2019@163.com","");
watch.Stop(); // 停止監視
Console.WriteLine("------------------------------------------------------------------------------2.程式結束");
TimeSpan timespan = watch.Elapsed; // 獲取當前例項測量得出的總時間
Console.WriteLine("主執行緒執行結束;費時:" + timespan.TotalMilliseconds + "(總毫秒數)");
Console.ReadLine();
}
/// <summary>
/// 啟動推送郵件執行緒池方法 2020-10-15 11:03 abel
/// </summary>
public static void ThreadUseAndConstruction()
{
//1.設定程式在執行時最小執行緒數和最大執行緒數
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(5, 5);
//2.查詢推送的郵箱使用者
DataTable dt = new DbHelperSQL(ServerDataDB).Query(SelectMailboxUser_SQL).Tables[0];
for (int i = 0; i < dt.Rows.Count; i++)
{
int code = int.Parse(dt.Rows[i]["ID"].ToString());
string subject = dt.Rows[i]["subject"].ToString();
string mailBody = dt.Rows[i]["mailBody"].ToString();
string toEmail = dt.Rows[i]["toEmail"].ToString();
string toEmailBCC = dt.Rows[i]["toEmailBCC"].ToString();
//3.把推送郵件的方法放入WaitCallback委託
WaitCallback callback = index =>
{
Stopwatch watch = new Stopwatch();
watch.Start(); //開始監視
StartSendMail(code, subject, mailBody, toEmail, toEmailBCC);
watch.Stop(); // 停止監視
TimeSpan timespan = watch.Elapsed; // 獲取當前例項測量得出的總時間
Console.WriteLine("編號:" + code + "的郵件推送結束;費時:" + timespan.TotalMilliseconds + "(總毫秒數)");
};
//4.線上程池中加入執行緒佇列
ThreadPool.QueueUserWorkItem(callback, i);
}
}
/// <summary>
/// 開始推送郵件 2020-10-15 10:30 abel
/// </summary>
/// <param name="code">使用者郵箱ID</param>
/// <param name="subject">主題</param>
/// <param name="mailBody">內容</param>
/// <param name="toEmail">接收人</param>
/// <param name="toEmailBCC">抄送人</param>
public static void StartSendMail(int code, string subject, string mailBody, string toEmail, string toEmailBCC)
{
bool SendState = new EmailHelper(toEmail, toEmailBCC, subject, mailBody, new string[0], userEmail, userPswd, mailServer).SendEmail();
if (SendState == true)
new DbHelperSQL(ServerDataDB).ExecuteSql(UpdateSendMailboxState_SQL, new SqlParameter[] { new SqlParameter("ID", code) });
}
/// <summary>
/// 查詢推送的郵件使用者 2020-10-15 10:52 abel
/// </summary>
private const string SelectMailboxUser_SQL = "select * from [dbo].[mailboxUser] where [State]=1";
/// <summary>
/// 更新郵件推送成功後的狀態 2020-10-15 10:50 abel
/// </summary>
private const string UpdateSendMailboxState_SQL = "update [dbo].[mailboxUser] set [State]='0',[Updater]='abel_2',[UpdateTime]=getdate() where [ID]=@ID";
}
C.Achievements
資源
百度網盤連結地址:https://pan.baidu.com/s/1_vJB3tXta42t52f39fAiZQ
提取碼:bhss
相關文章
- C# 多執行緒學習筆記 – 1C#執行緒筆記
- java多執行緒:執行緒池原理、阻塞佇列Java執行緒佇列
- 多執行緒學習-Disruptor佇列執行緒佇列
- java執行緒池-工作佇列workQueueJava執行緒佇列
- 執行緒池的阻塞佇列的理解執行緒佇列
- 執行緒池學習執行緒
- 執行緒池之ScheduledThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- 執行緒池之ThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- Java併發程式設計學習筆記----執行緒池Java程式設計筆記執行緒
- C#使用執行緒安全佇列ConcurrentQueue處理資料C#執行緒佇列
- Java幾種執行緒池及任務佇列Java執行緒佇列
- 踩坑 Spring Cloud Hystrix 執行緒池佇列配置SpringCloud執行緒佇列
- 探討阻塞佇列和執行緒池原始碼佇列執行緒原始碼
- 原始碼剖析ThreadPoolExecutor執行緒池及阻塞佇列原始碼thread執行緒佇列
- Python學習筆記 - 多執行緒Python筆記執行緒
- Linux程式執行緒學習筆記Linux執行緒筆記
- Java 多執行緒學習筆記Java執行緒筆記
- C#資料結構-執行緒安全佇列C#資料結構執行緒佇列
- 【java學習】ThreadPoolExecutor 執行緒池Javathread執行緒
- 深入學習執行緒池原理執行緒
- 執行緒池監控2-監控執行緒池狀態、執行緒數量和佇列任務數量等執行緒佇列
- Python學習筆記|Python之執行緒Python筆記執行緒
- Java多執行緒學習筆記(自用)Java執行緒筆記
- C#多執行緒開發-執行緒池03C#執行緒
- 證明執行緒池ThreadPoolExecutor的核心執行緒數,最大執行緒數,佇列長度的關係執行緒thread佇列
- 主佇列&主執行緒佇列執行緒
- 手寫執行緒池,對照學習ThreadPoolExecutor執行緒池實現原理!執行緒thread
- Java多執行緒學習(八)執行緒池與Executor 框架Java執行緒框架
- 三、執行緒池知識點整理筆記執行緒筆記
- 執行緒安全佇列(使用互斥鎖進行實現)執行緒佇列
- Java多執行緒-執行緒池的使用Java執行緒
- 物聯網學習教程——執行緒池執行緒
- 執行緒池的使用執行緒
- Python 執行緒池使用Python執行緒
- 手寫一個執行緒池,帶你學習ThreadPoolExecutor執行緒池實現原理執行緒thread
- Java併發程式設計筆記6:執行緒池的使用Java程式設計筆記執行緒
- Thinking in Java---多執行緒學習筆記(2)ThinkingJava執行緒筆記
- iOS 多執行緒--GCD 序列佇列、併發佇列以及同步執行、非同步執行iOS執行緒GC佇列非同步