1

필자가 작성한 응용 프로그램은 데이터베이스에 저장된 SMS 메시지를 보냅니다. 이 부분에서는 데이터베이스를 선택하고 대기중인 메시지를 HTTP 요청으로 보내는 Windows 서비스를 작성합니다.HTTP 요청을 보내기 위해 Windows 서비스 최적화

응용 프로그램이 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; 
    } 
+0

대량의 메시지를 보낼 수있는 API가 가능하지 않습니까? –

+0

대량 전송 방법이 있습니까? 그들은 그들의 API에 나열되어 있지 않습니다. – ijb109

+1

이 busy busy는 불필요하다. (while (tasks.Any (t =>! t.IsCompleted)) {}'). 'Task.WaitAll'을 사용할 수 있습니다. –

답변

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; 
+0

매번 새로운 연결을 만드는 부분은 잠재적으로 다른 키워드와 다른 수신자를 가진 일련의 데이터베이스를 순환합니다. 연결 사전을 만들면 어떤 이점이 있습니까? – ijb109

+0

이 경우 'System.Net.ServicePointManager.DefaultConnectionLimit = 20'이 문제를 해결했습니다. 나는 나머지를 다시 썼다. 그러나 그것은 주요 병목 현상을 수정했다. – ijb109

2

정말 많이 불타는하고있는 바쁜 대기의 종류 CPU.

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

실제로, 나는 카운트를 확인한 후 deque를 체크하기 때문에 예외없이 코드가 전혀 실행되지 않는다는 것을 이해하지 못합니다. 그러나 여러 스레드가 카운트를 하나씩 찾아서 모두 큐에서 제거하려고합니다. 그 중 하나를 제외하고 모두 실패 할 것입니다.

계속 진행하기 전에 멀티 스레딩의 기초를 배우기 시작해야한다고 생각합니다. 어떤 구체적인 조언은 아마도 코드가 버그로 인해 타격을 입었 기 때문에별로 도움이되지 않을 것입니다.".net을 사용하여 포크 결합 병렬 처리"에 대한 좋은 자습서를 찾고 TPL이 제공하는 기능을 찾으십시오.

여러 스레드가 안전하게 협력하고 서로 다른 데이터를 트램핑하는 방식을 이해하는 것이 중요합니다.

+0

감사합니다. 그게 내가 원하는거야, 나는 스레딩에 익숙하지 않다. – ijb109

0

Queue 대신에 ConcurrentQueue을 사용하십시오. 자세한 내용은 MSDN을 참조하십시오. 이것은 스레드 안전 구현이며 대부분 잠금이 필요하지 않으므로 매우 빠릅니다 ...

관련 문제