Web API MVC中的并发API发布请求问题

时间:2018-11-01 17:26:34

标签: asp.net-mvc asp.net-web-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 个答案:

答案 0 :(得分:0)

让我们根据假设进行研究。可能有2种不同的情况。

要记住的一般概念:

  1. 异步API端点
  2. 费率限制处理
  3. 并发控制,即每次调用API都会打开一个WebClient任务,并且CPU的线程池有限。如果将它们全部用尽,则可能是计算机崩溃,无响应,任务失败和取消。

让我们讨论场景。

场景1

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

API端点的实现方式应为:

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

关键部分是调用机制。应将其分解成块,并进行有效处理。为此,您可以使用Task.FactoryParallel.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的时间之后,这对您来说只是一个实现。