在asp.net中进行线程化

时间:2011-07-31 17:50:22

标签: asp.net multithreading

我有一个我为客户管理的网站,他们希望能够向所有会员发送电子邮件。我联系了主机,他们建议以每分钟50或更少的批量发送的方式编写它,这样邮件服务器就不会超载。

这听起来不错,但是我能想到的唯一方法就是在没有让管理员在每个批次之间发送电子邮件和重新加载的情况下必须坐在页面上这样做才能让页面调用一个ashx处理程序激活一个线程执行工作,并且线程在每个批处理后设置为休眠60秒。

当我从我的机器运行代码时,它工作正常并完成整个电子邮件列表。当我从Web主机运行它时,除了ftp之外我无法访问它,它几乎完成但没有。然后,如果我再次尝试打到ashx页面来完成任何未发送的页面,它就不会做任何事情。这就像线程可能导致锁定某些东西并使其他线程无法运行。

这是我正在使用的代码,我之前从未使用过线程......所以,是否有人知道它为什么会这样做以及如何使其正常工作?我完成后是否需要专门杀死线程?如果是这样,怎么样?感谢。

public void ProcessRequest(HttpContext context)
    {

        if (context.Request.QueryString["id"].IsValid<int>())
        {
            campaignId = context.Request.QueryString["id"].To<int>();
            var t = new Thread(new ThreadStart(SendEmails))
                        {
                            Priority = ThreadPriority.Lowest
                        };
            t.Start();
        }
    }

    private void SendEmails()
    {
        int currentCount = 0;
        BroadcastEmailCampaign campaign = EmailController.GetCampaign(campaignId, false);
        List<Member> memberlist = EmailController.GetEmailList(campaign.CampaignId);

        var message = new MailMessage
                          {
                              Body = campaign.Body,
                              From = new MailAddress(campaign.SentBy),
                              IsBodyHtml = true,
                              Subject = campaign.Subject,
                              BodyEncoding = Encoding.UTF8
                          };

        //add attachment
        if (!string.IsNullOrEmpty(campaign.Attachment) && File.Exists(campaign.Attachment))
        {
            var attachment = new Attachment(campaign.Attachment);
            EmailAttachmentType.SetContentProperites(campaign.Attachment, ref attachment);
            message.Attachments.Add(attachment);
        }

        if (memberlist.Count <= 0)
        {
            return;
        }

        bool sendingComplete = false;
        EmailController.SetCampaignSendingStatus(true, campaign.CampaignId);

        while (sendingComplete == false)
        {
            message.Bcc.Clear();
            message.To.Clear();

            message.To.Add(new MailAddress(dummyEmailAddress));

            List<Member> emailsToSend = memberlist.Skip(currentCount).Take(takeCount).ToList();

            if (emailsToSend.Count <= 0)
            {
                sendingComplete = true;
                EmailController.LogEmailCampaignResult(campaign);
                EmailController.SetCampaignSendingStatus(false, campaign.CampaignId);

            }

            if (!sendingComplete)
            {
                foreach (Member email in emailsToSend)
                {
                    message.Bcc.Add(new MailAddress(email.Email));
                    campaign.SentTo.Add(new BroadcastEmailCampaignSentTo
                                            {
                                                MemberId = email.MemberId,
                                                Email = email.Email,
                                                DateSent = DateTime.Now
                                            });
                }

                EmailController.SendEmail(message);
                EmailController.LogEmailsSent(emailsToSend, campaignId);

                currentCount += takeCount;

                Thread.Sleep(pauseTime);
            }
        }

    }

2 个答案:

答案 0 :(得分:1)

由于我在ASP.NET中阅读了大量的线程并且仍然没有真正的dos和donts线索,我通常会解决像你在Windows任务计划程序中作为计划任务运行的控制台应用程序所描述的任务,例如5分钟:

  1. 在ASP.NET页面中,我将所有必需的信息写入数据库表。
  2. 调度程序定期轮询数据库表以查找新作业(例如发送电子邮件)和进程,然后清空充当队列的数据库表。
  3. 这使我的应用程序能够保持响应,此外我不必担心IISRESET或类似的东西会杀死我的后台线程。

答案 1 :(得分:0)

t.IsBackground = TRUE;

如果不这样做,我建议将ThreadPool与QueueUserWorkItem一起使用。