在异常行为的异步 select 语句中限制并行任务执行
Throttled parallel task execution in async select statement with strange behaviour
在我的应用程序中,我想通过使用函数 AddDeviceAsync
添加从端口 10 开始的 20 个设备,该函数将 template
作为参数,用于创建具有名称的实际设备template.Name
通过联系端口 port
.
我正在使用 SemaphoreSlim 来防止通过同时添加到许多设备来耗尽系统。
using (var semaphore = new SemaphoreSlim(10))
{
var tasks = Enumerable.Range(startPort, devicesCount).Select(
async port =>
{
try
{
await semaphore.WaitAsync().ConfigureAwait(false);
template.Name = $"{device.Name} {port}";
template.CommunicationSettings.Port = port;
await this.equipmentNewApplicationService.AddDeviceAsync(template).ConfigureAwait(false);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ConfigureAwait(false);
}
不过我的代码出了点问题,因为一旦开始节流 (deviceCount
= 20)
一些设备共享它们的名称:
DeviceName-10
DeviceName-11
DeviceName-12
DeviceName-13
DeviceName-14
DeviceName-14
DeviceName-14
DeviceName-17
注意:只有设备名称错误 - 设备连接到正确的端口。
我怀疑这与 select
中的 async closure
有某种联系,但我实在想不通。
如果没有理由在外部范围内声明 template
(而且似乎没有),则将其移入您的 Select
:
using (var semaphore = new SemaphoreSlim(10))
{
var tasks = Enumerable.Range(startPort, devicesCount).Select(async port =>
{
try
{
await semaphore.WaitAsync();
var template = new Template
{
Name = $"{device.Name} {port}",
CommunicationSettings.Port = port
};
await this.equipmentNewApplicationService.AddDeviceAsync(template);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ConfigureAwait(false);
}
因为 Select
正在产生多个任务,可能 运行 在多个线程上,否则会出现尝试更新 template
.
的竞争条件
此外,在 lambda 中使用 ConfigureAwait(false)
是多余的,因为没有任何死锁风险。
在我的应用程序中,我想通过使用函数 AddDeviceAsync
添加从端口 10 开始的 20 个设备,该函数将 template
作为参数,用于创建具有名称的实际设备template.Name
通过联系端口 port
.
我正在使用 SemaphoreSlim 来防止通过同时添加到许多设备来耗尽系统。
using (var semaphore = new SemaphoreSlim(10))
{
var tasks = Enumerable.Range(startPort, devicesCount).Select(
async port =>
{
try
{
await semaphore.WaitAsync().ConfigureAwait(false);
template.Name = $"{device.Name} {port}";
template.CommunicationSettings.Port = port;
await this.equipmentNewApplicationService.AddDeviceAsync(template).ConfigureAwait(false);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ConfigureAwait(false);
}
不过我的代码出了点问题,因为一旦开始节流 (deviceCount
= 20)
一些设备共享它们的名称:
DeviceName-10
DeviceName-11
DeviceName-12
DeviceName-13
DeviceName-14
DeviceName-14
DeviceName-14
DeviceName-17
注意:只有设备名称错误 - 设备连接到正确的端口。
我怀疑这与 select
中的 async closure
有某种联系,但我实在想不通。
如果没有理由在外部范围内声明 template
(而且似乎没有),则将其移入您的 Select
:
using (var semaphore = new SemaphoreSlim(10))
{
var tasks = Enumerable.Range(startPort, devicesCount).Select(async port =>
{
try
{
await semaphore.WaitAsync();
var template = new Template
{
Name = $"{device.Name} {port}",
CommunicationSettings.Port = port
};
await this.equipmentNewApplicationService.AddDeviceAsync(template);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ConfigureAwait(false);
}
因为 Select
正在产生多个任务,可能 运行 在多个线程上,否则会出现尝试更新 template
.
此外,在 lambda 中使用 ConfigureAwait(false)
是多余的,因为没有任何死锁风险。