我有很多请求要发送到服务器(亚马逊产品广告API),但是这个服务器不允许我每秒发送超过1个请求。 我正在寻找一种基于C#技能的免费解决方案。
我试着像这样编码:
public static WebResponse Request(Dictionary<string, string> parameters) {
var response = LaunchRequest(parameters);
Sleep(1000);
return response;
}
问题是多个线程正在进入方法&#34; Request&#34;同时。如果有4个线程,那么每秒将有4个请求。
我的线程如何相互等待?
编辑:我试了锁。
所以我写了这段代码:
public class RequestHandler {
private static readonly RequestHandler instance = new RequestHandler();
private Object thisLock = new Object();
private RequestHandler() { }
public static RequestHandler Instance {
get {
return instance;
}
}
public WebResponse Request(Dictionary<string, string> parameters) {
lock (thisLock) {
Log();
var response = LaunchRequest(parameters);
Sleep(1000);
return response;
}
}
}
所以我这样称呼我的方法:
// ...
RequestHandler requestHandler = RequestHandler.Instance;
WebResponse response = requestHandler.Request(requestHelper, parameters);
// ...
它似乎在大部分时间都有效,但有时候,我的&#34; LaunchRequest&#34;方法几乎同时被解雇。
编辑2: 以下是日志结果,箭头显示的是小于1秒的调用:
Request: 09:52:50.230 - Thread 22
Request: 09:52:48.830 - Thread 5
Request: 09:52:47.468 - Thread 10 <---
Request: 09:52:47.331 - Thread 13 <---
Request: 09:52:45.971 - Thread 12
Request: 09:52:44.767 - Thread 11
Request: 09:52:43.230 - Thread 5
Request: 09:52:30.546 - Thread 21 <---
Request: 09:52:30.357 - Thread 20 <---
Request: 09:52:29.232 - Thread 13
Request: 09:52:27.908 - Thread 11
Request: 09:52:26.471 - Thread 5
Request: 09:52:25.138 - Thread 11
Request: 09:52:23.835 - Thread 12
答案 0 :(得分:2)
创建SQS队列。 在控制器中,将数据放入队列。 创建一个.net服务,该服务将逐个轮询队列并处理消息,确保在任何给定时间只发送一条消息。
UPD 如果您不喜欢AWS服务,不确定为什么要将帖子标记为AWS,但仍然如此。
您可以使用任何可用的不同队列,而不是SQS,例如MSMQ,RabbitMQ等。成本需要自己安装和维护。
绝对最糟糕的情况,使用C#中的ConcurrentQueue
类型,并运行将从该队列弹出的后台线程。这将确保一次只处理一条消息。但是,此解决方案不具备弹性,因为应用程序池回收会擦除您的数据。
答案 1 :(得分:2)
将最后的通话详细信息存储在会话或本地变量中。如果有电话,你可以打电话给睡眠。
public static WebResponse Request(Dictionary<string, string> parameters)
{
lock (thisLock)
{
string lastCalled = Session["LastCalledTime"] as string;
if (!string.IsNullOrEmpty(lastCalled) && DateTime.Parse(lastCalled) >= DateTime.Now.AddSeconds(-1))
{
Sleep(1000);
}
var response = LaunchRequest(parameters);
Session["LastCalledTime"] = DateTime.Now.ToString("O");
}
return response;
}
添加锁以使其线程安全,如trailmax所示。