web-API-mvc中并发API请求后问题



最近,我在并发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);           
}

让我们来假设一下。可能有两种不同的情况。

需要牢记的一般概念:

  1. 异步API端点
  2. 费率限制处理
  3. 并发控制,即每次调用API时,它都会打开WebClient任务,并且CPU具有有限的Threadpools。如果你用尽了所有这些,那么你的计算机可能会崩溃、没有响应、任务失败和取消

让我们讨论一下这些场景

场景1

  1. 您有一个API端点,您正在从另一个应用程序调用它
  2. 您正在并行/并发调用它

API端点应实现为:

public async Task<IHttpActionResult> YourAPIMethod() { //The wait able processing }

关键部分是调用机制它应该被分成块,并得到有效的处理。为此,您可以使用Task.FactoryParallel.Task Library。不要急于创建循环中的任务。

假设我必须同时调用一个api端点100次。我必须设计一个机制来做到这一点。我不能简单地同时创建100个web请求任务。示例逻辑为:

1.决定要同时处理的块大小 2。让它们同时处理,但按块处理

假设我有一个CPU,它有4个内核和16个虚拟处理器。所以对我来说,最好的区块大小在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和线程池时,这将是您的一部分实现。

最新更新