我正在编写的应用程序发送存储在数据库中的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;
}
答案 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
。它是一个线程安全的实现,因此非常快速无锁...