我了解有关多线程和使用线程池的概念。我试图弄清楚的一个概念是如何跟踪每个线程上发送的电子邮件。想象一下,每个线程负责提取 x 条记录,遍历这些电子邮件,应用电子邮件模板,然后将电子邮件保存到提取目录。显然,我需要一种方法来告诉每个线程不要提取与另一个线程相同的数据。
我考虑的一个解决方案是对数据进行分页,使用全局变量或数组来跟踪已发送到的页面,让每个线程检查该变量并从下一个可用页面开始。我能想到的唯一问题是,如果数据发生变化,可用页面可能会不同步。
另一种解决方案是在数据库中设置一个 bool 值以确定是否已向某个帐户发送电子邮件。因此,EF 将提取 X 条记录并将这些记录更新为准备好通过电子邮件发送。这样每个查询只会查找尚未准备好通过电子邮件发送到的电子邮件。
如果可能的话,我想获得一些其他建议,或者扩展我提供的解决方案。
最佳答案
假设有一天您可能想要扩展到多个应用服务器,内存同步实现可能也不足以保证电子邮件不重复。
最简单的解决方法之一是在数据库级别实现批处理机制。
在一个工作单元下
- 读取 N x 条记录,使用悲观锁定(即防止拉取相同电子邮件的其他线程并发读取)
- 用批处理 ID(或
IsProcessed
指示符)标记这些记录 - 将记录返回给您的应用
例如SQL Server 中的批处理 PROC 可能类似于(假设表 = dbo.Emails,它有一个 PK EmailId 和一个已处理的指示器 BIT 字段 IsProcessed
):
CREATE PROC dbo.GetNextBatchOfEmails
AS
BEGIN
-- Identify the next N emails to be batched. UPDLOCK is to prevent another thread batching same emails
SELECT top 100 EmailId
INTO #tmpBatch
FROM dbo.Emails WITH (UPDLOCK)
WHERE IsProcessed = 0
-- Stamp emails as sent. Assumed that PROC is called under a UOW. The batch IS the UOW
UPDATE e
SET e.IsProcessed = 1
FROM dbo.Emails e
INNER JOIN #tmpBatch t
on e.EmailId = t.EmailId
-- Return the batch of emails to caller
SELECT e.*
FROM dbo.Emails e
INNER JOIN #tmpBatch t
on e.EmailId = t.EmailId
END
然后将 PROC 公开为映射到您的电子邮件实体的 EF 函数导入。在 TransactionScope
ts 下,您可以调用 EF 函数导入,发送电子邮件,并在成功时调用 ts.Complete()。
关于c# - 使用 Entity Framework 构建一个简单的多线程时事通讯引擎,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12131535/