我正在使用API来获取数据并将其存储在数据库中。问题是API每次调用只返回50条记录,因此为了在更短的时间内获得更多数据,我们在应用程序中使用了 Parallel.For 。我在下面使用的代码在大多数情况下成功地将数据保存在数据库中,但在极少数情况下抛出异常。它在极少数情况下抛出的例外是
tasks数组包含至少一个null元素。参数名称:任务|在System.Threading.Tasks.Task.WaitAll(Task [] tasks,Int32 millisecondsTimeout,CancellationToken cancellationToken)处于System.Threading.Tasks.Task.WaitAll(Task [] tasks,Int32 millisecondsTimeout)。
我不知道异常的原因,因为大部分时间它都给出了正确的结果,我可以将数据保存在数据库中。下面是我写的代码。请帮我解决这个问题,我是并行编程的新手。
object objobject = new object();
public void GetDataConcurrent()
{
var tasks = new List<Task>();
ParallelOptions objParallelOptions = new ParallelOptions();
CancellationTokenSource objCancellationTokenSource = new CancellationTokenSource();
objParallelOptions.MaxDegreeOfParallelism = 3;
objParallelOptions.CancellationToken = objCancellationTokenSource.Token;
string CompletePostData = "PostData to send to API";
string tException = string.Empty;
int noOfrequests = 15;
string jsonResponse=string.Empty;
try
{
Parallel.For(0, noOfrequests, objParallelOptions, (ChangeSetValue) =>
{
tasks.Add(Task.Factory.StartNew(() =>
{
var webRequest = WebRequest.Create("http://urlofAPI");
webRequest.ContentType = "application/json";
webRequest.Method = "POST";
webRequest.Proxy = WebRequest.DefaultWebProxy;
webRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
POSTDATA objPOSTDATA = new POSTDATA();
objPOSTDATA.CompletePostData = CompletePostData + ",'ChangeSetValue':'" + (ChangeSetValue) + "'}";
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(objPOSTDATA);
var datatoSend = Encoding.UTF8.GetBytes(json);
webRequest.GetRequestStream().Write(datatoSend, 0, datatoSend.Length);
webRequest.GetReponseAsync().ContinueWith(t =>
{
if (t.Exception == null)
{
using (var sr = new StreamReader(t.Result.GetResponseStream()))
{
lock (objobject)
{
string str = sr.ReadToEnd();
jsonResponse = jsonResponse + str;
jsonResponse = jsonResponse.Replace("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", string.Empty);
jsonResponse = jsonResponse.Replace("</string>", string.Empty);
jsonResponse = jsonResponse.Substring(1, jsonResponse.Length - 2);
SaveData();// Method to Save Data in Database by Deserializing the JSON Response
jsonResponse = string.Empty;
}
}
}
else
{
tException = t.Exception.InnerException.Message;
}
}).Wait();
}));
});
Task.WaitAll(tasks.ToArray());
}
catch (OperationCanceledException ex)
{
LogException(InsertLogInformation(ex.Message));
}
catch (AggregateException ex)
{
for (int j = 0; j < ex.InnerExceptions.Count; j++)
{
LogException(InsertLogInformation(ex.Message));
}
}
catch (Exception ex)
{
LogException(InsertLogInformation(ex.Message));
}
}
public void SaveData()
{
//Method to Save Data in DataBase
}
public static class WebRequestExtensions
{
public static Task<WebResponse> GetReponseAsync(this WebRequest request)
{
return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
}
}
public class POSTDATA
{
public string CompletePostData { get; set; }
}
答案 0 :(得分:3)
要扩展@ ta.speot.is的评论(因为没有人似乎想要添加这个问题的答案)。问题是您要添加到Parallel.For
内的tasks数组。 List<T>
不是线程安全的,因此您应该使用锁定语句同步对List<T>.Add
的调用。
我不确定的另一件事是你在Parallel.For
内创建任务的原因。 Parallel.For
将自己创建任务,因此您可以完全取消任务列表。