1

私が書いているアプリケーションは、データベースに保存されているSMSメッセージを送信します。この部分では、選択したデータベースを調べて、待機中のメッセージをHTTP要求として送信するWindowsサービスを作成しています。

アプリケーションはSMSを送信しているため、速度が重要です。現在、1秒あたり約15件のリクエストしか送信されていません。現在、アプリケーションSMSMessagesはそれらを作成して同期キューに入れます。マルチスレッドを使用して、そのキューから一度に20スレッドを実行します。

実行するスレッドが多すぎると、アプリケーションが実際に1秒あたりに送信されるメッセージの数を遅くすることに気づきました。

私が理解しようとしているのは、リクエストを送信するために私が行っているよりも速い方法があるかどうかです。スレッドを整理するためのより良い方法はありますか、それともアプリケーションを最適化するためにスレッドプーリングまたは非同期リクエストを使用する必要がありますか?

メインコードはここにあります:

            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

そして、あなたが再利用した場合はどうなりますか

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

物体?

接続パラメータは呼び出し間で変更されません。静的フィールドにするのは良い考えだと思いますか?

[編集]

たとえばRequest、静的フィールドとして定義します。

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

または、 `リクエストオブジェクトの辞書でさえ:

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 に答える
2

あなたがしているようなビジーウェイトは、実際に多くのCPUを消費しています。

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

実際、カウントをチェックしてから両端キューを作成するため、例外なくコードがどのように実行されるかはまったくわかりません。ただし、複数のスレッドがカウントを1つと見なし、すべてがデキューを試みる場合があります。それらの1つを除いてすべてが失敗するでしょう。

先に進む前に、マルチスレッドの基本を今すぐ学び始める必要があると思います。コードにはバグがたくさんあるので、具体的なアドバイスはおそらくあまり役​​に立ちません(私が言及した2つ以外にもあります)。「.netを使用したフォーク結合の並列処理」に関する優れたチュートリアルを見つけて、TPLによって提供される機能を見つけてください。

複数のスレッドが安全に連携し、互いのデータを踏みにじらないようにする方法を理解することが重要です。

于 2012-12-12T22:06:21.633 に答える
0

QueueたとえばConcurrentQueue-の使用を使用する代わりに、詳細については、 MSDNを参照してください。これはスレッドセーフな実装であり、ほとんどロックフリーであるため、非常に高速です...

于 2012-12-12T22:42:56.737 に答える