Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 部分工作已完成两次(ThreadPool.QueueUserWorkItem)_C#_Asp.net_Threadpool - Fatal编程技术网

C# 部分工作已完成两次(ThreadPool.QueueUserWorkItem)

C# 部分工作已完成两次(ThreadPool.QueueUserWorkItem),c#,asp.net,threadpool,C#,Asp.net,Threadpool,我已经创建了一个通讯系统,允许我指定哪些成员应该收到通讯。然后,我循环浏览符合条件的成员列表,为每个成员生成一条个性化消息,并异步向他们发送电子邮件 发送电子邮件时,我使用的是ThreadPool.QueueUserWorkItem 出于某种原因,一部分成员收到了两次电子邮件。在我的上一批邮件中,我只向712名成员发送了邮件,但最终总共发送了798条 我正在记录发送出去的消息,我可以告诉大家,前86名成员收到了两次消息。这是日志(按照消息发送的顺序) 但是,每个成员都应该收到一次新闻稿,因为您可

我已经创建了一个通讯系统,允许我指定哪些成员应该收到通讯。然后,我循环浏览符合条件的成员列表,为每个成员生成一条个性化消息,并异步向他们发送电子邮件

发送电子邮件时,我使用的是
ThreadPool.QueueUserWorkItem

出于某种原因,一部分成员收到了两次电子邮件。在我的上一批邮件中,我只向712名成员发送了邮件,但最终总共发送了798条

我正在记录发送出去的消息,我可以告诉大家,前86名成员收到了两次消息。这是日志(按照消息发送的顺序)

但是,每个成员都应该收到一次新闻稿,因为您可以看到成员163992收到消息#1和#86;成员163993收到消息#2和#87;等等

另外需要注意的是,在发送消息85和86之间有7秒的延迟

我已经检查了几次代码,排除了几乎所有的代码是导致它的原因,除了
ThreadPool.QueueUserWorkItem

这是我第一次使用ThreadPool,所以我对它不太熟悉。是否可能存在某种导致这种行为的竞争条件

==---代码示例--===

检查事项(我假设你有办法模仿发送电子邮件):

  • 重复电子邮件的数量总是完全相同吗?如果增加/减少输入值的数量会怎么样?重复的用户ID是否总是相同的
  • sendmail()
    做了什么有意义的事吗?(我看不到你的代码)
  • 您不使用的原因是什么

  • 在没有多线程的情况下,您会得到相同的行为吗

无论如何,从你自己的网站发送大量电子邮件——即使是完全合法的——并不总是值得麻烦。垃圾邮件拦截服务非常具有攻击性,您不希望您的域最终被列入黑名单。第三方服务消除了这一风险,提供了许多工具,还可以为您管理这一部分流程。

您确定正在运行的查询中没有重复的成员列表以获取发送电子邮件的目的吗?你要加入另一张桌子吗?你能做的是:

List<DomainObjects.Members.MemberEmailNotificationInfo> list = GetListFromDatabase();
list = list.Distinct().ToList();
List List=GetListFromDatabase();
list=list.Distinct().ToList();
如果此代码:

foreach (var recipient in recipientsToEmail)
{
    _emailSender.SendMemberRegistrationActivationReminder(eventArgs.Newsletter
    ,eventArgs.RecipientNotificationInfo, previewEmail: string.Empty);
}

符合您实际正在做的事情。。。你有一个明显的错误。也就是说,您正在执行foreach,但没有使用返回值,因此您将向
事件args发送相同的电子邮件。对于
收件人电子邮件中的每个条目,RecipientNotificationInfo

在将任务排入后台线程的代码中执行两次任务的一个常见原因是错误处理。您可以仔细检查您的代码,以确保如果出现错误,无论错误类型如何,您都不会重试(有些错误需要重试,而其他错误则不需要重试)

话虽如此,你发布的代码没有包含足够的信息来明确回答你的问题;有很多可能性


FWIW,您是否知道
SmtpClient
类有一个
SendAsync()
方法,它不需要使用单独的工作线程?

在服务器上运行800多个线程不是一个好做法! 尽管您使用的是线程池,但只要旧线程返回到线程池并释放资源,线程就会在服务器上排队并运行。在服务器上这可能需要几分钟,在这段时间内可能会发生许多情况,如竞争条件或并发。 您可以在一个受保护列表上对一个工作项进行排队:

lock (recipientsToEmail)
{
    ThreadPool.QueueUserWorkItem(t =>
        {
            // enumerate recipientsToEmail and send email
        });
}

在您的代码示例中,我们看不到您的日志记录发生在哪里

可能发送电子邮件的方法错误地认为发生了错误,然后系统再次尝试,这可能导致发送两次电子邮件


另外,如其他答案和评论中所述,我将再次检查收件人列表中是否没有重复的条目,并在非并行上下文中进行测试。

对我来说就像竞争条件-如果使用队列,是否在调用ThreadPool.QueueUserWorkItem()之前从队列中删除项目?我们可以看看你的代码吗?我没有使用任何其他类型的队列。基本上:循环浏览满足要求的成员列表,为成员生成电子邮件,添加对实际向ThreadPool发送电子邮件的方法的调用。为了避免重复,请维护有电子邮件挂起的用户列表,几乎不可能说出任何信息。我建议发布说明问题的代码。
recipientsToEmail
是否可能只包含两次收件人ID?我想我真正的问题是“你确定使用
ThreadPool.QueueUserWorkItem
会导致复制吗?”Tim,实际上SendEmail会记录邮件的内容,这样他们就可以“在线查看”。我不知道SmtpClient有一个SendAsync方法,我将切换到该方法。另外,我实际上正在使用SendGrid来处理电子邮件的传递。我只是在我的网站上生成邮件,并使用他们的SMTP服务器。“在没有多线程的情况下,你会得到相同的行为吗?”这是我的第一点,同时检查列表中重复的项目。当我发送新闻稿时,我利用了电子邮件系统,该系统在一次发送一条邮件时已经存在。我真的没有想过,但是,是的,拥有800多个线程似乎是一个错误的方法。我重新编写了我的代码,这样我就可以创建一个新的线程,并让它处理时事通讯消息。
foreach (var recipient in recipientsToEmail)
{
    _emailSender.SendMemberRegistrationActivationReminder(eventArgs.Newsletter
    ,eventArgs.RecipientNotificationInfo, previewEmail: string.Empty);
}
lock (recipientsToEmail)
{
    ThreadPool.QueueUserWorkItem(t =>
        {
            // enumerate recipientsToEmail and send email
        });
}