首页 > 解决方案 > IsCancellationRequested 始终为 false

问题描述

我正在使用 Task.Whenall().I 并行调用相同的函数,并且正在尝试添加功能以使用 CancellationTokenSource 停止执行。CancellationTokenSource 在我调用 Token.Cancel() 时返回 true,但之后它变为 false,因此 token.IsCancellationRequested 始终为 false。

    CancellationTokenSource _tokenSource = new CancellationTokenSource();
    [HttpPost]
            public async Task<IActionResult> Runcase(List<string> products,string runnumber,string button)
            {
              var token = _tokenSource.Token;
                try
                {
                    if (ModelState.IsValid)
                    {
                        var productinfo = products;
                        List<string> productids = new List<string>(productinfo);
                        var runnum = runnumber;
                        string runid = "";
                        int count = productids.Count();
                        List<Task> tasks = new List<Task>();
                        int rawid = 0;
                         for (int i = 0; i < count; i++)
                            {
                               tasks.Add(RunServiceAsync(productids[i], runnum,rawid,token));
                            }
                        
                        await Task.WhenAll(tasks);
                        ViewBag.completed = "Success";
                        return View();
                    }
                    else
                    {
                        ViewBag.productinfo = new MultiSelectList(_context.inputValuesConfigurations, "ProductID", "ProductName");
                        ModelState.AddModelError(string.Empty, "Please enter a valid data...");
                        return View();
                    }
                }
                catch(Exception ex)
                {
                    return View();
                }
            }

当我调用此函数时,令牌返回 true

 public void Stopexecution()
        {
            _tokenSource.Cancel();
        }

但是在下面的代码中它总是错误的

public async Task RunServiceAsync(string productids,string runnumber,int rawid,CancellationToken token)
        {
            using(var dbscope = _service.CreateScope())
            {
                var dbcontext = dbscope.ServiceProvider.GetRequiredService<AppDbContext>();
                var productid = Convert.ToInt32(productids);
                var inputvals = dbcontext.inputValuesConfigurations.FirstOrDefault(m => m.ProductID == productid);
                var run = runnumber + '_' + inputvals.ProductID;
                int count = 0;
                bool completion1 = false; // for j
                int totalCount = CountProductvalues(inputvals);
                while (!completion1) // 
                {
                    var errorrun = dbcontext.errorlogs.Select(m => m.ProductID == productid).ToList().Count();
                    totalCount = completion == true ? errorrun : totalCount;
                    for (int j = rawid; j < totalCount; j++)
                    {
                        if(token.IsCancellationRequested)
                        {
                            token.ThrowIfCancellationRequested();
                        }
                        if(!completion) // Stop if First run complete
                        {
                            Inputvalues c1 = new Inputvalues(j, inputvals);
                            InputValuesViewmodel inputValues = new InputValuesViewmodel()
                            {
                                ProductID = productid,
                                STATE = c1.State,
                                AGE1 = c1.AGE1,
                                SEX1 = c1.SEX1,
                                UND_CLASS1 = c1.UND_CLASS1,
                                FACE_OPTIONS = 1,
                                FACE_SCHEDULE = "1ü" + c1.SOLVE_TARGET_YEAR + "0ü" + c1.FACE_SCHEDULE,
                                PREM_OPTIONS = premoption,
                                PAY_PREM_TARGET_ID = c1.PAY_PREM_TARGET_ID,
                                PAY_PREM_TARGET_YEAR = c1.PAY_PREM_TARGET_YEAR,
                                SOLVE_TARGET_ID = 1,
                                SOLVE_TARGET_YEAR = c1.SOLVE_TARGET_YEAR
                            };
                            await RecieveResponseasync(inputValues, run, j,productid);
                            
                            //completion = j == totalCount ? true : false;
                        }
                    }
                };
            }
        }

打电话Stopexecution()

$("#btnstop").click(function (e) {
                    
                    $("#btnstart span").text("Rerun");
                    let btnstartval = $("#btnstart").val('Rerun');
                    e.preventDefault();
                    $.ajax({
                        url: "@Url.Action("Stopexecution", "CallService")",
                        type: "POST",
                        dataType: "json",
                    });
                });
            });

标签: c#asp.netmodel-view-controller.net-core

解决方案


所以这里的第一个问题是你有一个CancellationTokenSource作为控制器的成员。控制器是瞬态的,这意味着每次向它发出请求时都会创建它们。因此,每次调用该控制器时,您都会创建一个新的令牌源。

要解决此问题,您可以将其设为静态:

static CancellationTokenSource _tokenSource = new CancellationTokenSource();

记住每次发出请求时都要重置该源......因为一旦它被取消,它就会被永久取消。此外,如果此端点同时被调用两次或更多次,会发生什么情况。您将有一个比赛条件。

第二个问题是:这不是一个非常“类似控制器”的模式。您应该重新考虑如何生成数据。如果对端点的调用超过 100 毫秒,那么如果您的服务变热,您将遇到线程/套接字饥饿问题。


推荐阅读