线程池优化

问题描述 投票:1回答:1

我正在开发一个发送大量电子邮件的多线程异步表单应用程序。我几乎完成了该应用程序,但对性能有所担心。如果您以更好的最佳实践启发我,那将是完美的,并且我将在初级开发人员的基础上真正地学习基础知识。

这里是问题:首先,我有用于触发Windows.Forms.Timer组件的应用程序的“开始”按钮。

private void btnStart_MouseClick(object sender, MouseEventArgs e)
{
    timerNewCampaignChecker.Tick += new EventHandler(timerNewCampaignChecker_Tick);
    timerNewCampaignChecker.Enabled = true;
    timerNewCampaignChecker.Start();
}

应用程序需要每3秒检查一次数据库以查找新的广告系列(第一种方法),内联定制广告系列详细信息(第二种)以供用户输入,然后通过电子邮件将广告系列发送给收件人(第三种方法)。为了每3秒检查一次数据库以查看新的广告系列,我有上面的计时器(间隔为3秒),它通过检查新的广告系列来启动流程:

MethodInvoker invoker;
private void timerNewCampaignChecker_Tick(object sender, EventArgs e)
{
    invoker = new MethodInvoker(CheckNewCampaigns);
    invoker.BeginInvoke(null, null);
}

因此,计时器每3秒触发一次CheckNewCampaigns方法,并从第一步开始。 从计时器本身启动流和ThreadPool结构是否正确?? 。

delegate bool StepCaller(int campaignID);
private void CheckNewCampaigns()
{   
    StringBuilder builder = new StringBuilder();
    StepCaller stepCaller = new StepCaller(PrepareCampaignEmail);
    IEnumerable<Campaigns> CampaignsList = DatabaseManager.GetCampaignsList(DatabaseManager.GetNewCampaigns());

    foreach (Campaigns Campaign in CampaignsList)
    {
        stepCaller.BeginInvoke(Campaign.CampaignID, new AsyncCallback(PrepareEmailCallback), null); 
    }
}

我必须在第一种方法中编写endInvoke的代码,还是我应该开除并忘记??

。因为最重要的是应用程序具有流程,所以方法之间会传递参数,因此第二个方法应该知道第一个方法何时完成,以便可以获取campaignID并对其进行自定义。但是,在进行这些操作时,应该首先启动新流程并检查新的广告系列。并且电子邮件应同时发送。New方法(第二个方法)定制广告系列,并使用ThreadPool调用另一个方法(第三个方法)。这是:
private bool PrepareCampaignEmail(int campaignID)
{
    EmailCaller emailCaller = new EmailCaller(SendEmail);
    IEnumerable<Subscribers> SubscribersList = DatabaseManager.GetCampaignSubscribersList(DatabaseManager.GetCampaignSubscribers(campaignID)); 
    CampaignCustomazition campaignCustomizer;
    List<CampaignCustomazition> campaignCustomizedList = new List<CampaignCustomazition>();  // foreach in içindeki beginInvoke ı dışarıya çıkardığımda kullanılacak
    foreach (Subscribers subscriber in SubscribersList)
    {
        campaignCustomizer = new CampaignCustomazition(campaignID);
        campaignCustomizer.CustomizeSource(campaignID, out campaignCustomizer.source, out campaignCustomizer.format);
        campaignCustomizer.CustomizeCampaignDetails(campaignID, out campaignCustomizer.subject, out campaignCustomizer.fromName, out campaignCustomizer.fromEmail, out campaignCustomizer.replyEmail);
        campaignCustomizer.CustomizeSubscriberDetails(campaignID, out campaignCustomizer.subscriberID, out campaignCustomizer.email, out campaignCustomizer.fullName);
        IAsyncResult result = emailCaller.BeginInvoke(campaignCustomizer, null, null);
        try
        {
            emailCaller.EndInvoke(result);
        }
        catch(Exception ex)
        {
            Trace.WriteLine(ex.Message);
        }
    }
    return false;
}

我想这是第二步中的一个主要问题。数据库操作几乎是5-6次。这可能是线程的问题。似乎工作正常,但我的方法可能是错误的。一天可能会有数十个广告活动。这是一个问题,还是我的方法还行?(DB操作并不是那么苛刻和复杂)。

准备好电子邮件后,就可以发送了,上面已经提到了。第三种方法是发送电子邮件并将其记录的简单SMTP方法。

此最后一个方法也不具有EndInvoke功能,但这是应用程序的最后一个方法,因为刚刚发送了邮件。

我处理计时器和ThreadPool的方式对您来说是否合乎逻辑?如何以最佳方式测试性能并优化线程池的工作?您可以针对上述任何方面提出建议和教益吗?

非常感谢。

我正在开发一个发送大量电子邮件的多线程异步表单应用程序。我几乎完成了该应用程序,但对性能有所担心。如果您能更好地启发我...

c# multithreading timer threadpool
1个回答
2
投票

首先,您应该意识到.NET具有多种计时器选项,可以根据需要进行选择。当您希望在UI线程上执行回调时使用System.Windows.Forms.Timer(因为您需要以任何方式刷新UI)。 System.Timers.Timer和System.Threading.Timer都在后台线程上执行回调。您可以在此MSDN article中详细了解这些内容。

documentation中所述,使用BeginInvoke异步执行委托时,应始终调用EndInvoke。若要以一劳永逸的方式执行方法,建议的方法是使用ThreadPool.QueueUserWorkItem(.NET 4之前)或Task.TaskFactory.StartNew(.NET 4)。后者的优点是线程和任务之间没有1:1的关联-调度程序将选择“适当”数量的线程来使用,并为您调度在这些线程上执行的任务。

© www.soinside.com 2019 - 2024. All rights reserved.