使用 index in for like 参数生成 List<Task>
Generate List<Task> with using index in for like parameter
我想生成 List<Task>
然后并行调用它。我尝试这样做,但不明白如何在 lambda 表达式中传递索引。在我看来,总是发送 for
的最后一个索引。但是我想在并行计算中使用所有索引...
List<Task> tasks = new List<Task>();
var valueSize = Values.Count;
for (int i = 1; i <= valueSize; i++)
{
tasks.Add(Task.Factory.StartNew(
() => {
this.Values[i] = this._tcpRepository.GetValueAsync(i).ToString().GetInt32();
}));
}
Task.WaitAll(tasks.ToArray());
附加信息:
public Dictionary<int, int> Values { get; set; }
在 TcpRepository 中
public async Task<string> GetValueAsync(int digit)
{
var netStream = this.TcpClient.GetStream();
if (netStream.CanWrite)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes(digit.ToString());
await netStream.WriteAsync(sendBytes, 0, sendBytes.Length);
}
if (netStream.CanRead)
{
byte[] bytes = new byte[this.Client.ReceiveBufferSize];
await netStream.ReadAsync(bytes, 0, (int)this.Client.ReceiveBufferSize);
return bytes.ToString();
}
return null;
}
GetInt32()
这是我对字符串 public static int GetInt32(this string value)
的自定义扩展。字符串可以作为不是数字的字符出现垃圾。
这里有一些问题。
要直接回答您的问题,您需要在 i
上创建一个闭包,以防止在您的异步代码中访问它之前对其进行更新。
您可以通过将 for
循环替换为 Enumerable.Range
来实现。
另一个问题是您 运行 GetValueAsync
在 ThreadPool 上但没有等待它。随后,您的 Task.WaitAll
将仅等待外部 Task
,而不是 GetValueAsync
.
返回的 Task
这是您可以执行的操作的示例:
var tasks = Enumerable.Range(0, valueSize)
.Select(async i =>
{
string val = await _tcpRepository.GetValueAsync(i);
Values[i] = val.GetInt32();
});
你的最后一个问题是Task.WaitAll
的使用;这引入了 sync-over-async 反模式。您应该允许异步通过您的代码库增长,而不是使用 Task.WhenAll
,其中 returns 一个 Task
在所有提供的 Task
完成时完成:
await Task.WhenAll(tasks);
我想生成 List<Task>
然后并行调用它。我尝试这样做,但不明白如何在 lambda 表达式中传递索引。在我看来,总是发送 for
的最后一个索引。但是我想在并行计算中使用所有索引...
List<Task> tasks = new List<Task>();
var valueSize = Values.Count;
for (int i = 1; i <= valueSize; i++)
{
tasks.Add(Task.Factory.StartNew(
() => {
this.Values[i] = this._tcpRepository.GetValueAsync(i).ToString().GetInt32();
}));
}
Task.WaitAll(tasks.ToArray());
附加信息:
public Dictionary<int, int> Values { get; set; }
在 TcpRepository 中
public async Task<string> GetValueAsync(int digit)
{
var netStream = this.TcpClient.GetStream();
if (netStream.CanWrite)
{
Byte[] sendBytes = Encoding.UTF8.GetBytes(digit.ToString());
await netStream.WriteAsync(sendBytes, 0, sendBytes.Length);
}
if (netStream.CanRead)
{
byte[] bytes = new byte[this.Client.ReceiveBufferSize];
await netStream.ReadAsync(bytes, 0, (int)this.Client.ReceiveBufferSize);
return bytes.ToString();
}
return null;
}
GetInt32()
这是我对字符串 public static int GetInt32(this string value)
的自定义扩展。字符串可以作为不是数字的字符出现垃圾。
这里有一些问题。
要直接回答您的问题,您需要在 i
上创建一个闭包,以防止在您的异步代码中访问它之前对其进行更新。
您可以通过将 for
循环替换为 Enumerable.Range
来实现。
另一个问题是您 运行 GetValueAsync
在 ThreadPool 上但没有等待它。随后,您的 Task.WaitAll
将仅等待外部 Task
,而不是 GetValueAsync
.
Task
这是您可以执行的操作的示例:
var tasks = Enumerable.Range(0, valueSize)
.Select(async i =>
{
string val = await _tcpRepository.GetValueAsync(i);
Values[i] = val.GetInt32();
});
你的最后一个问题是Task.WaitAll
的使用;这引入了 sync-over-async 反模式。您应该允许异步通过您的代码库增长,而不是使用 Task.WhenAll
,其中 returns 一个 Task
在所有提供的 Task
完成时完成:
await Task.WhenAll(tasks);