使用Entity Framework构建简单的多线程新闻稿引擎

时间:2012-08-26 15:53:09

标签: c# multithreading entity-framework

我理解多线程和使用线程池的概念。我想弄清楚的一个概念是如何跟踪每个线程上发送的电子邮件。因此,想象一下,每个线程负责提取x个记录,迭代这些电子邮件,应用电子邮件模板,然后将电子邮件保存到提取目录。显然,我需要一种方法来告诉每个线程不要将另一个线程提取相同的数据。

我想到的一个解决方案是分页数据,有一个全局变量或数组来跟踪已发送到的页面,让每个线程检查该变量并从下一个可用页面开始。我能想到的唯一问题是,如果数据发生变化,那么可用的页面可能会不同步。

另一种解决方案是在数据库中设置一个布尔值,以确定是否已通过电子邮件发送帐户。因此,EF会提取X条记录并将这些记录更新为准备发送电子邮件。这样,每个查询只会查找尚未准备好通过电子邮件发送到的电子邮件。

如果可能的话,我想获得一些其他建议,或者扩展我提供的解决方案。

2 个答案:

答案 0 :(得分:3)

鉴于您可能有一天想要扩展到多个应用服务器,内存同步实施可能还不足以保证电子邮件不会重复。

解决的最简单方法之一是在数据库级实现批处理机制。

在工作单元下

  • 使用悲观锁定读取N x条记录(即阻止其他线程同时读取相同的电子邮件)
  • 使用批次ID(或IsProcessed指示符)
  • 标记这些记录
  • 将记录退回到您的应用

e.g。 SQL服务器中的批处理PROC可能看起来像(假设table = 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()。

答案 1 :(得分:2)

除了nonnb的方法之外,如果您希望使用SQL Server 2005 +,则可以在一个语句中完成所有操作。

;WITH q AS
(
   SELECT TOP 10 * 
   FROM dbo.your_queue_table
   WHERE
       IsProcessing = 0
   --you can obviously include more filtering criteria to meet your needs
)

UPDATE q WITH (ROWLOCK, READPAST)
SET IsProcessing = 1
OUTPUT INSERTED.*

关于将数据库表用作队列,还有一些关于here的重要信息。