优化Windows服务以发送HTTP请求

时间:2012-12-12 21:34:03

标签: c# multithreading optimization windows-services threadpool

我正在编写的应用程序发送存储在数据库中的SMS消息。对于这部分,我正在编写一个Windows服务,它将通过一系列数据库,然后将等待的消息作为HTTP请求发送。

因为应用程序正在发送短信,速度很重要。现在,我每秒只发送大约15个请求。现在,应用程序创建SMSMessages,然后将它们放入同步队列中。我使用多线程从该队列一次运行20个线程。

我注意到如果我运行太多线程,那么应用程序实际上减慢了每秒发送的消息数量。

我想弄清楚的是,是否有比我发送请求更快的方式。有没有更好的方法来组织我的线程,还是应该使用线程池或异步请求来优化应用程序?

主要代码在这里:

            Queue Messages = new Queue();
            DataRow[] Rows = dtSMSCombined.Select(); //Created from a datatable
            foreach (DataRow Row in Rows)
            {
                ... //Get information from the row.

                SMSMessage oSMS = new SMSMessage(Keyword, Number, Message, MessageID);
                Messages.Enqueue(oSMS);
            }

            Queue SyncedMessages = Queue.Synchronized(Messages);
            var tasks = new Task[20];

            for (int i = 0; i < 20; i++)
            {
                tasks[i] = Task.Factory.StartNew(() =>
                    { //each thread will pull out new items from the queue as they finish
                        while (SyncedMessages.Count > 0)
                        {
                            Response = new XDocument();
                            SMSMessage oSMS = (SMSMessage)SyncedMessages.Dequeue();

                            if (oSMS.GetMessage() != null && oSMS.GetMessage() != string.Empty)
                            {
                                Response = oSMS.SendSMS();
                            }
                            string ResponseCode = (string)Response.Descendants("response").First();
                            if (ResponseCode == "ok")
                            {
                                oSMS.sResponseCode = ResponseCode;
                                oSMS.dCompleted = DateTime.Now;
                            }
                            else { }

                            oSMS.DTInsert();
                        }
                    });
            }

            while (tasks.Any(t => !t.IsCompleted)) { }

以下是SendSMS()类中的SMSMessage方法:

    public XDocument SendSMS()
    {
        XML = "<message id=\""+ lMessageID +"\"><partnerpassword>" + PartnerPassword + "</partnerpassword><content>" + sMessage + "</content></message>";
        URL = "http://sloocetech.net:****/spi-war/spi/" + PartnerID + "/" + sRecipient + "/" + Keyword + "/messages/mt";
        HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);
        Request.Proxy = null;

        RequestBytes = System.Text.Encoding.ASCII.GetBytes(XML);
        Request.Method = "POST";
        Request.ContentType = "text/xml;charset=utf-8";
        Request.ContentLength = RequestBytes.Length;
        RequestStream = Request.GetRequestStream();
        RequestStream.Write(RequestBytes, 0, RequestBytes.Length);
        RequestStream.Close();

        HttpWebResponse Resp = (HttpWebResponse)Request.GetResponse();
        oReader = new StreamReader(Resp.GetResponseStream(), System.Text.Encoding.Default);
        string backstr = oReader.ReadToEnd();

        oReader.Close();
        Resp.Close();

        Doc = XDocument.Parse(backstr);
        return Doc;
    } 

3 个答案:

答案 0 :(得分:2)

如果你重复使用

怎么办?
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);

对象?

连接参数在调用之间不会更改。你觉得把它变成一个静态的领域是个好主意吗?

<强> [编辑]

例如,您将Request定义为静态字段:

static HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("http://www.google.com");

或者,甚至是`Request objects:

的字典
static Dictionary<string,HttpWebRequest> Requests = new Dictionary<string,HttpWebRequest>();

然后,在您的SendSMS()方法中:

public XDocument SendSMS()
{
    XML = "<message id=\"" + lMessageID + "\"><partnerpassword>" + PartnerPassword + "</partnerpassword><content>" + sMessage + "</content></message>";
    URL = "http://sloocetech.net:****/spi-war/spi/" + PartnerID + "/" + sRecipient + "/" + Keyword + "/messages/mt";

    //check if the request object exists
    if (!Requests.Keys.Contains(sRecipient))
        Requests.Add((HttpWebRequest)WebRequest.Create(URL));

    //get the existing request from the dictionary
    Requests = Requests[sRecipient];

    //configure the request
    Request.Proxy = null;
    RequestBytes = System.Text.Encoding.ASCII.GetBytes(XML);
    Request.Method = "POST";
    Request.ContentType = "text/xml;charset=utf-8";
    Request.ContentLength = RequestBytes.Length;
    RequestStream = Request.
    RequestStream.Write(RequestBytes, 0, RequestBytes.Length);
    RequestStream.Close();

    using (System.IO.Stream RequestStream = Request.GetRequestStream())
    {
        using (WebResponse response = Request.GetResponse())
        {
            using (oReader = new StreamReader(Resp.GetResponseStream(), System.Text.Encoding.Default))
            {
                string backstr = oReader.ReadToEnd();
                Doc = XDocument.Parse(backstr);
            }
        }
    }

    return Doc;
}

<强> [编辑]

也许你也应该玩下面的静态字段:

System.Net.ServicePointManager.DefaultConnectionLimit = 20;

答案 1 :(得分:2)

你正在做的那种忙碌的等待真的烧掉了很多CPU。

while (tasks.Any(t => !t.IsCompleted)) { }

实际上,我不明白你的代码是如何运行的,没有例外,因为你检查了计数,然后检查了deque。但是多个线程可能会发现计数为1,并且所有线程都会尝试出列。除了其中一个之外的所有人都会失败。

我认为您应该在继续之前开始学习多线程的基础知识。任何具体的建议可能都没有多大帮助,因为代码是如此缠绕着bug(除了我提到的两个之外还有其他的)。尝试找到一个关于“fork join parallelism with .net”的好教程,并找出TPL提供的功能。

重要的是要了解多个线程如何安全地协作而不是践踏彼此的数据。

答案 2 :(得分:0)

有关详细信息,请参阅MSDN,而不是使用Queue,例如使用ConcurrentQueue。它是一个线程安全的实现,因此非常快速无锁...

相关问题