c# - 使用任务索引超出范围异常

标签 c# task-parallel-library task

我正在使用 Task.FromAsync 和 Task.ContinueWith 方法来完成我的工作。我在我的程序中使用了一个列表,当我运行它时,它给了我一个索引超出范围异常。但是,当我通过调试器时,它会运行并完成。将任务与循环和列表一起使用时,我是否遗漏了什么或它们的运行方式不同?

public int TimerCounter = 0;
public IList<WebsiteResult>webResult = new List<WebsiteResult>();

public void sendRequest(){
    foreach(Website web in TempVar._allWebsites)
    {
        webResult.Add(new WebSiteResult {});
        try
        {
        pageCheck(web);
        webResult.ElementAt(TimerCounter).RequestSentTime = DateTime.Now.ToString();
        if(webResult.ElementAt(TimerCounter).SystemStatus == null)
            webResult.ElementAt(TimerCounter).SystemStatus = "";

        TimeCounter++;
    }
}



public void pageCheck(){
    IAsyncResult asyncResult;
    Uri uri = new Uri(TempURL); //TempUrl is assigned a string beforehand
    HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(uri);
    try{
        Task<WebResponse> task = Task.Factory.FromAsync(
            myReq.BeginGetResponse,
            asyncResult => myReq.EndGetResponse(asyncResult),
            (Object)null);

        task.ContinueWith(t =>
            {
                var responseCode = (HttpWebResponse)t.Result;
                ReadStreamFromResponse(t.Result);
                if(responseCode.StatusCode == HttpStatusCode.OK){
                  webResult.ElementAt(TimerCounter).ResponseStatusCode = "Up"; //Error occurs here
                  reponseCode.Close();
                }
            }
        );
}
//catch exceptions
}

private String ReadStreamFromResponse(WebResponse response) {
    StreamReader responseStream = new StreamReader(response.GetResponseStream());
    string str = responseStream.ReadToEnd();
    return str;
}

最佳答案

这是因为您对 pageCheck() 的调用设置了一个延续,它将在 Task 结束/完成时运行。但是,对 pageCheck() 方法的调用将在设置和结束您的 Task 后立即返回给调用者 (sendRequest()) >。您的 Task 将需要时间在后台线程池线程上执行,但会很快将控制返回给 sendRequest(),然后它会尝试访问您的 IList 将没有元素,因为这些元素是在延续中填充的。这可能工作有时取决于线程池优化器如何分派(dispatch)Task 以及任务需要多长时间。如果您逐步使用调试器,这会影响 Task 的触发方式,并会影响操作的顺序 - 因此 同样会影响这些操作的结果。

我的建议是把你的

task.ContinueWith(t =>
    {
        var responseCode = (HttpWebResponse)t.Result;
        ReadStreamFromResponse(t.Result);
        if(responseCode.StatusCode == HttpStatusCode.OK)
        {
            webResult.ElementAt(TimerCounter).ResponseStatusCode = "Up"; //Error occurs here
            reponseCode.Close();
        }

        webResult.ElementAt(TimerCounter).RequestSentTime = DateTime.Now.ToString();
        if(webResult.ElementAt(TimerCounter).SystemStatus == null)
            webResult.ElementAt(TimerCounter).SystemStatus = "";
        TimeCounter++;
     });

进入 pageCheck() 内的延续。另一种选择是创建另一种方法,将此过程包装在“更高级别的任务”中,您将设置 Task 并在 sendRequest() 中继续方法代替。

请注意,在这种情况下使用锁对您没有帮助,因为您不知道何时会施加锁。它可能不会影响执行顺序,您的问题仍然存在。

希望对您有所帮助。

关于c# - 使用任务索引超出范围异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17449926/

相关文章:

multithreading - 生成比线程更多的任务

javascript - gulp watch 不看

c# - 在 LINQ 中,如何对来自 .Include() 的数据执行 .OrderBy()?

c# - 如何正确使用 HttpClient 和 async/await?

c# - 使用任务并行库时线程数增长

c# - PCL 中的 TPL 和监视器

c# - 正确的投票方式?

用于冗余库的 C# .NET 包装器程序集开发

c# - asp-for TagHelper结合反射的使用方法

c# - GridView 中的数据绑定(bind)