3

我正在使用 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;
}
4

1 回答 1

2

这是因为您的调用pageCheck()设置了将在Task完成/完成时运行的延续。但是,在设置pageCheck()sendRequest()关闭您的Task. 您Task将需要时间在后台线程池线程上执行,但会sendRequest()快速返回控制权,然后尝试访问您的IList没有元素,因为这些元素会在后续中填充。这有时可能会起作用,具体取决于线程池优化器如何调度以及任务需要多长时间。如果您逐步使用调试器,这可能会影响TaskTask被解雇并且可以影响操作的顺序 - 所以再次可以影响这些操作的结果。

我的建议是把你的

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()

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

我希望这有帮助。

于 2013-07-03T14:28:18.903 回答