最近我在并发api post请求中遇到了一个主要问题,一次请求100个。是否有任何选项可以一个接一个地处理该请求,即一个请求已完成,然后另一个请求将要执行? 我已经使用了异步任务,但是没有更好的反馈。请给我建议解决这个问题。
更新:添加我的api代码
[System.Web.Http.HttpPost]
[System.Web.Http.Route("api/test/Create")]
public async Task<IHttpActionResult> Create([FromBody]TestModel getmodel)
{
Dictionary<object, object> dict = new Dictionary<object, object>();
Int64 companyCode = 101, usercode = 10101001, a = 0;
if (TokenInfo.TokenCheck(companyCode, usercode, getmodel.token))
{
using (var transaction = db.Database.BeginTransaction())
{
try
{
MainModel model = new MainModel();
model.COMPID = 101;
model.CARDDT = carddt;
model.CARDYY = getyear;
model.PSGRNM = Convert.ToString(agent);
model.CARDCID = Convert.ToString(101001);
model.ROUTE = getmodel.route;
model.AGENTID = agent;
model.REMARKS = getmodel.remarks;
model.MOBNO = getmodel.mobile_No;
model.TICKETLTP = "Null";
Int64 max_cardno =
Convert.ToInt64(
await
db.modelDbSet.Where(x => x.COMPID == 101 && x.CARDYY == getyear)
.MaxAsync(x => x.CARDNO));
if (max_cardno == 0)
{
string aa = Convert.ToString(getmodel.year);
model.CARDNO = aa.Substring(2, 2) + "00001";
model.CARDID = model.COMPID + "10202" + model.CARDNO;
}
else
{
model.CARDNO = Convert.ToString(max_cardno + 1);
model.CARDID = model.COMPID + "10202" + model.CARDNO;
}
Int64 length = Convert.ToInt64(model.CARDNO.Length);
if (length == 7)
{
db.modelDbSet.Add(model);
await db.SaveChangesAsync();
transaction.Commit();
dict.Add(key:"data",value:model.CARDNO);
dict.Add(key: "success", value: true);
dict.Add(key: "message", value: "Data Saved Successfully.");
return Ok(dict);
}
dict.Add(key: "success", value: false);
dict.Add(key: "message", value: "Card No must be 7 digit.");
return Ok(dict);
}
catch (Exception ex)
{
transaction.Rollback();
dict.Add(key: "success", value: false);
dict.Add(key: "message", value: ex.Message);
return Ok(dict);
}
}
}
dict.Add(key: "success", value: false);
dict.Add(key: "message", value: "Authorized not permitted.");
return Ok(dict);
}
答案 0 :(得分:0)
让我们根据假设进行研究。可能有2种不同的情况。
要记住的一般概念:
让我们讨论场景。
场景1
API端点的实现方式应为:
public async Task<IHttpActionResult> YourAPIMethod()
{
//The wait able processing
}
关键部分是调用机制。应将其分解成块,并进行有效处理。为此,您可以使用Task.Factory
或Parallel.Task Library
。不要急于循环创建任务。
假设我必须同时调用api端点100次。我必须设计一种机制来做到这一点。我不能简单地同时创建Web请求的100个任务。示例逻辑为:
1。确定要同时处理的块大小 2。让它们并发但分块处理
假设我有一个具有4个核心和16个虚拟处理器的CPU。因此,对我而言,最佳块大小在4-6之间。所以我的代码应该像这样:
var chunk = GetMaxChunkSize();
Parallel.For(0, 100, new ParallelOptions() { CancellationToken = CancellationToken.None,
MaxDegreeOfParallelism = chunk
}, () => {
//Process the HttpRequest here either using WebClient or HTTPClient
});
或者您可以将Parallel.Foreach与ParallelOptions一起使用
Parallel.Foreach(yourIEnumerableCollection, new ParallelOptions() { CancellationToken = CancellationToken.None,
MaxDegreeOfParallelism = chunk
}, () => {
//Process the HttpRequest here either using WebClient or HTTPClient
});
方案1:外部API的速率限制例外
或者,如果您希望使用更通用的Task.Factory来调用API,那么您将需要付出更多努力。您必须Skip()
和Take()
来自特定集合。将它们添加到块大小的任务列表中。处理该任务列表,然后继续下一个迭代。 sudo代码为
var chunk = GetChunkSize(); //Finding chunk size
var iterator = 1; // helpful in building our logic
var lstMaxSize = Collection.Count(); // Calculation the collection length
List<Task> taskCollection = new List<Task>(); // the completed task collection
Task[] processingArray = new Task[chunk]; //initialize the new Array of the chunk size
foreach(var item in collection)
{
if(iterator == chunk){ //if iterator value is equal to our chunk
Task.WaitAll(processingArray); //wait the queued task to complete
taskCollection.AddRange(processingArray.ToList()); //copy the queued task in main list
iterator = 1; //re-initialize the iterator
processingArray = new Task[chunk]; //re-initialize the processingArray
}
var task = Task.Factory.StartNew(()=>{
//Same call the API endpoint here
});
processingArray[iterator++] = task; //adding the task in the processingArray
}
if(iterator < chunk) //Case where our processingArray have some remaining task and the loop is completed
{
Task.WaitAll(processingArray);
taskCollection.AddRange(processingArray.ToList());
}
这是我们用于处理速率限制异常并同时高效处理任务的实现。在您了解了CPU和threadPool的时间之后,这对您来说只是一个实现。