1

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

因为应用程序正在发送 SMS,所以速度很重要。现在,我每秒只收到大约 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;
    } 
4

3 回答 3

2

The kind of busy-waiting that you are doing is really burning a lot of CPU.

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

Actually, I don't understand how your code runs at all without exceptions because you check the count and then deque. But multiple threads might find the count to be one and all try to dequeue. All but one of them would be failing.

I think you should start to learn the basics of multi-threading now before you proceed. Any concrete advice would probably not help much because the code is so ridden with bugs (there are others than the two I mentioned). Try to find a good tutorial on "fork join parallelism with .net" and find out what features are provided by the TPL.

It is important to understand how multiple threads can cooperate safely and not trample over each others data.

于 2012-12-12T22:06:21.633 回答
2

如果你重复使用

HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);

目的?

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

[编辑]

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

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

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

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;
于 2012-12-12T22:01:28.323 回答
0

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

于 2012-12-12T22:42:56.737 回答