首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >优化Windows服务以发送HTTP请求

优化Windows服务以发送HTTP请求
EN

Stack Overflow用户
提问于 2012-12-13 05:34:03
回答 3查看 3.1K关注 0票数 1

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

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

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

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

主要代码如下:

代码语言:javascript
复制
            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)) { }

下面是来自SMSMessage类的SendSMS()方法:

代码语言:javascript
复制
    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;
    } 
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-12-13 06:01:28

如果您重用

代码语言:javascript
复制
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);

对象?

连接参数在两次调用之间不会更改。您认为将其设置为静态字段是个好主意吗?

编辑

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

代码语言:javascript
复制
static HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("http://www.google.com");

或者,甚至是一个` `Request对象的字典:

代码语言:javascript
复制
static Dictionary<string,HttpWebRequest> Requests = new Dictionary<string,HttpWebRequest>();

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

代码语言:javascript
复制
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;
}

编辑

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

代码语言:javascript
复制
System.Net.ServicePointManager.DefaultConnectionLimit = 20;
票数 2
EN

Stack Overflow用户

发布于 2012-12-13 06:06:22

你正在做的这种忙碌的等待确实消耗了大量的CPU。

代码语言:javascript
复制
while (tasks.Any(t => !t.IsCompleted)) { }

实际上,我根本不明白你的代码是如何在没有异常的情况下运行的,因为你先检查计数,然后再排队。但多个线程可能会发现计数为1,并且所有线程都会尝试出队。除了其中一人,其他人都会失败。

我认为你现在应该开始学习多线程的基础知识,然后再继续。任何具体的建议可能都不会有太大帮助,因为代码中充满了错误(除了我提到的两个之外,还有其他的错误)。尝试找到一个关于“使用.net实现fork join并行”的很好的教程,并找出第三方公共关系提供了哪些特性。

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

票数 2
EN

Stack Overflow用户

发布于 2012-12-13 06:42:57

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13849042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档