【发布时间】:2020-04-30 08:43:54
【问题描述】:
我在调用任务列表中的方法时遇到问题。我有一种方法可以创建 N 个任务。在每个任务中,我都会执行一些操作,最终通过HttpWebRequest 获取数据并将该数据写入文件。我使用锁定对象来锁定对变量等共享资源的访问。除了调用创建一个执行HttpWebRequest(方法GetData)的方法之外,一切都执行得很好。每当我不锁定该方法的调用 (GetData) 时,似乎都会跳过一些数据/文件。例如:
- 使用锁定对象,我得到文件 1、2、3 和 4
- 没有锁定对象我得到文件 2,4 和 3
这是创建任务的方法的代码
private object lockObjectWebRequest= new object();
private object lockObjectTransactions = new object();
public List<Task> ExtractLoanTransactionsData(string URLReceived, string Headers, string Body)
{
List<Task> Tasks = new List<Task>();
try
{
int Limit = 0;
int OffsetItemsTotal = 0;
int NumberOftasks = 4;
// Create the task to run in parallel
for (int i = 0; i <= NumberOftasks; i++)
{
int OffsetCalculated = 0;
if (i > 0)
{
OffsetCalculated = Limit * i;
}
Tasks.Add(Task.Factory.StartNew(() =>
{
string URL = URLReceived+ "&offset=" + OffsetCalculated .ToString() + "&limit=" + Limit.ToString();
string Output = string.Empty;
lock (lockObjectWebRequest)
{
Output = GetData(URL, Headers,Body);
}
if (Output != "[]")
{
lock (lockObjectTransactions)
{
Identifier++;
Job.Identifier = Identifier;
// write to file
string json = JValue.Parse(Output).ToString(Formatting.Indented);
string FileName = OffSet.ToString() + Identifier;
string Path = @"C:\FileFolder\" + FileName + ".json";
File.WriteAllText(Path, json);
}
}
}));
}
}
catch (Exception ex)
{
Tasks = new List<Task>();
}
return Tasks;
}
这是执行HttpWebRequest的代码:
public string GetData(string URL, string Headers, string Body)
{
string Data = string.Empty;
Headers = Headers.Trim('{').Trim('}');
string[] HeadersSplit = Headers.Split(new char[] { ',', ':' });
HttpWebRequest WebRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
WebRequest.Credentials = new NetworkCredential();
WebRequest.Method = "POST";
HttpWebResponse WebResponse;
// Set necessary Request Headers
for (int i = 0; i < HeadersSplit.Length; i = i + 2)
{
string HeaderPart1 = HeadersSplit[i].Replace("\"", "").Trim();
string HeaderPart2 = HeadersSplit[i + 1].Replace("\"", "").Trim();
if (HeaderPart1 == "Content-Type")
{
WebRequest.ContentType = HeaderPart2;
}
else if (HeaderPart1 == "Accept")
{
WebRequest.Accept = HeaderPart2;
}
else if (HeaderPart1 == "Authorization")
{
WebRequest.Headers["Authorization"] = HeaderPart2;
}
}
WebRequest.Headers.Add("cache-control", "no-cache");
// Add body to Request
using (var streamWriter = new StreamWriter(WebRequest.GetRequestStream()))
{
streamWriter.Write(Body);
streamWriter.Flush();
streamWriter.Close();
}
// Execute Request
WebResponse = (HttpWebResponse)WebRequest.GetResponse();
// Validate Response
if (WebResponse.StatusCode == HttpStatusCode.OK)
{
using (var streamReader = new StreamReader(WebResponse.GetResponseStream()))
{
Data = streamReader.ReadToEnd();
}
}
return Data;
}
我在这里做错了什么?该方法没有任务之间共享的全局数据。
【问题讨论】:
-
首先请永远不要写
catch (Exception ex)。这是一个糟糕的反模式。您应该只捕获您可以有意义地处理的特定异常。您应该始终防御性地编码以避免首先出现异常。 -
您的问题中有很多代码。理想情况下,您应该尝试删除与问题无关的任何行,并保留仍然足以重现问题的绝对最小值。这将使您的问题更容易回答。
-
@TheodorZoulias 我认为显示所有代码以查看流程会更容易。我还包含了 GetData 方法的代码,因为当我调用此方法时,似乎会发生问题,所有创建的任务都没有锁定对象。
-
@AtomicBrownie - 看到不必要的东西并不容易。如果您必须在任务中添加
lock,这似乎是完全错误的。锁定所有的 IO 是疯狂的。您需要提供minimal reproducible example。 -
Maarten 的回答是我向您建议的。它应该使您能够删除所有锁。我看不到您需要锁定的任何其他共享资源。也就是说,您的代码中有未定义的变量。我无法复制、粘贴和编译您的代码。所以我不知道是否还有其他事情发生。你能提供一个minimal reproducible example吗?
标签: c# multithreading task