正在寻找与 async/await 一起使用的 Reader 写入器锁
Looking for a Reader Writer Lock that works with async/await
我正在将旧应用程序移植到 .NET Core。我需要一个 reader 写锁(很多读操作,偶尔写操作)。我的旧代码是大量多线程的,所以旧的 ReaderWriterLock 工作得很好。新代码是基于任务的,所以我试图接受 async/await 模式。
这让我想到了锁定原语的需要。旧的锁定原语仅在您等待单个线程时才有效。有一个任务感知的 SemaphoreSlim,但我不知道如何将其用于 Reader 写入器锁。
我发现了这个:AsyncReaderWriterLock,但我找不到任何使用示例或任何似乎在使用它的人。如果我可以使用 Microsoft 的东西,我不想使用 Stephen Cleary 的库。那么,这里的故事是什么?是否有支持 reader 编写器锁定的 .NET 多任务原语?我应该避免使用 AsyncReaderWriterLock 有什么理由吗?有没有人看到它工作的例子?
I don't want to use Stephen Cleary's library if I can use something from Microsoft.
我也是。
So, what's the story here?
VS-Threading library 有一段历史。它最初是 VS-SDK 的一部分,旨在用于(并且仅授权用于)VS 扩展。这并没有阻止人们找到它并用他们自己的应用程序分发它,我曾多次建议不要这样做。如今,它已独立成自己的项目,可在 NuGet 上使用,并获得 MIT 许可。所以我觉得这几天用着没问题。但这就是历史,我认为历史是它没有被广泛采用的原因。
Is there a .NET multi-tasking primitive that supports reader writer locking?
不作为框架的一部分(至少,现在还不是)。有 AsyncEx, VS-Threading, and roll-your-own。我不确定 VS-Threading 在 Microsoft 支持方面存在于何处 - 即,它是否由特定团队维护?我确实在最近的提交中看到了 Andrew Arnott 和 Sam Harwell,他们都是这个领域的天才,所以我想说现在掌握得很好。我只是不确定它是多么正式的 Microsoft 项目。
Is there a reason I should avoid using AsyncReaderWriterLock?
当然可以。我通常反对 reader/writer 锁。原因是很多开发者认为"some of my code reads, and some of my code writes, and so I need a RWL",其实不然。还有其他要求:读取的数量必须远远超过写入的数量,并且读取的数量必须至少有压倒写入的数量。如果不满足这些附加要求,那么一个简单的锁就可以了。对于异步代码尤其如此;在执行 I/O.
时持有锁并不常见
Has anyone seen an example of it working?
其实我没有,这有点好笑。但是看着 the source,我会说调用 await ReadLockAsync
/await WriteLockAsync
然后处理结果值以释放锁。例如:
using (var releaser = await arwl.ReadLockAsync())
{
... // code using await
}
AsyncEx 和 roll-your-own 方法的用法相同。
晚会有点晚了,但是..
我也不得不处理这个问题。所有解决方案都使用 Tasks 而不是 ValueTask 结合 IDisposable 释放器。 (所以你总是要等待它)
如果不需要,我宁愿不等待就尝试获取锁。所以我想出了一个不同的方法,将一个函数传递给它,该函数将在锁内执行。
一个 ReadersWriterLock Async returns 一个 ValueTask。所以当直接拿锁的时候,就不用等待了。
此库将按请求的顺序处理锁。它还支持在启动它的 SynchronizationContext 上继续。 (对 UI 个线程有用)
我同意 “异步代码尤其如此;在执行 I/O 时持有锁并不常见。”
事实是,您可以使用异步代码等待锁中的代码执行完毕,并在需要时等待它。这并不意味着锁中的代码必须是异步的。
这是一个例子:
class Program
{
static async Task Main(string[] args)
{
var rwl = new AsyncReadersWriterLock();
Console.WriteLine("* Example 1");
// run example 1
var result1 = Example1(rwl);
if (!result1.IsCompleted)
await result1;
Console.WriteLine("");
Console.WriteLine("* Example 2");
// run example 2
var result2 = Example2(rwl);
if (!result2.IsCompleted)
await result2;
}
private static async ValueTask Example1(AsyncReadersWriterLock rwl)
{
Console.WriteLine("Before calling UseReaderAsync");
var result = rwl.UseReaderAsync(async () =>
{
Console.WriteLine("Reader start");
await Task.Delay(1000);
Console.WriteLine("Reader end");
});
Console.WriteLine("After calling UseReaderAsync");
Console.WriteLine("");
if (!result.IsCompleted)
{
Console.WriteLine("result.IsCompleted == false, awaiting");
await result;
Console.WriteLine("await finished");
}
else
Console.WriteLine("result.IsCompleted == true, no await is used");
}
private static async ValueTask Example2(AsyncReadersWriterLock rwl)
{
Console.WriteLine("Before calling UseReaderAsync");
var result = rwl.UseReaderAsync(() =>
{
Console.WriteLine("Reader start");
// no async is used
//await Task.Delay(1000);
Console.WriteLine("Reader end");
});
Console.WriteLine("After calling UseReaderAsync");
Console.WriteLine("");
if (!result.IsCompleted)
{
Console.WriteLine("result.IsCompleted == false, awaiting");
await result;
Console.WriteLine("await finished");
}
else
Console.WriteLine("result.IsCompleted == true, no await is used");
}
}
导致:
* Example 1
Before calling UseReaderAsync
Reader start
After calling UseReaderAsync
result.IsCompleted == false, awaiting
Reader end
await finished
* Example 2
Before calling UseReaderAsync
Reader start
Reader end
After calling UseReaderAsync
result.IsCompleted == true
我还在努力。 (我对 github/creating nuget 包没有太多经验,所以欢迎任何想法)
包裹:nuget
来源:github
我正在将旧应用程序移植到 .NET Core。我需要一个 reader 写锁(很多读操作,偶尔写操作)。我的旧代码是大量多线程的,所以旧的 ReaderWriterLock 工作得很好。新代码是基于任务的,所以我试图接受 async/await 模式。
这让我想到了锁定原语的需要。旧的锁定原语仅在您等待单个线程时才有效。有一个任务感知的 SemaphoreSlim,但我不知道如何将其用于 Reader 写入器锁。
我发现了这个:AsyncReaderWriterLock,但我找不到任何使用示例或任何似乎在使用它的人。如果我可以使用 Microsoft 的东西,我不想使用 Stephen Cleary 的库。那么,这里的故事是什么?是否有支持 reader 编写器锁定的 .NET 多任务原语?我应该避免使用 AsyncReaderWriterLock 有什么理由吗?有没有人看到它工作的例子?
I don't want to use Stephen Cleary's library if I can use something from Microsoft.
我也是。
So, what's the story here?
VS-Threading library 有一段历史。它最初是 VS-SDK 的一部分,旨在用于(并且仅授权用于)VS 扩展。这并没有阻止人们找到它并用他们自己的应用程序分发它,我曾多次建议不要这样做。如今,它已独立成自己的项目,可在 NuGet 上使用,并获得 MIT 许可。所以我觉得这几天用着没问题。但这就是历史,我认为历史是它没有被广泛采用的原因。
Is there a .NET multi-tasking primitive that supports reader writer locking?
不作为框架的一部分(至少,现在还不是)。有 AsyncEx, VS-Threading, and roll-your-own。我不确定 VS-Threading 在 Microsoft 支持方面存在于何处 - 即,它是否由特定团队维护?我确实在最近的提交中看到了 Andrew Arnott 和 Sam Harwell,他们都是这个领域的天才,所以我想说现在掌握得很好。我只是不确定它是多么正式的 Microsoft 项目。
Is there a reason I should avoid using AsyncReaderWriterLock?
当然可以。我通常反对 reader/writer 锁。原因是很多开发者认为"some of my code reads, and some of my code writes, and so I need a RWL",其实不然。还有其他要求:读取的数量必须远远超过写入的数量,并且读取的数量必须至少有压倒写入的数量。如果不满足这些附加要求,那么一个简单的锁就可以了。对于异步代码尤其如此;在执行 I/O.
时持有锁并不常见Has anyone seen an example of it working?
其实我没有,这有点好笑。但是看着 the source,我会说调用 await ReadLockAsync
/await WriteLockAsync
然后处理结果值以释放锁。例如:
using (var releaser = await arwl.ReadLockAsync())
{
... // code using await
}
AsyncEx 和 roll-your-own 方法的用法相同。
晚会有点晚了,但是..
我也不得不处理这个问题。所有解决方案都使用 Tasks 而不是 ValueTask 结合 IDisposable 释放器。 (所以你总是要等待它) 如果不需要,我宁愿不等待就尝试获取锁。所以我想出了一个不同的方法,将一个函数传递给它,该函数将在锁内执行。
一个 ReadersWriterLock Async returns 一个 ValueTask。所以当直接拿锁的时候,就不用等待了。
此库将按请求的顺序处理锁。它还支持在启动它的 SynchronizationContext 上继续。 (对 UI 个线程有用)
我同意 “异步代码尤其如此;在执行 I/O 时持有锁并不常见。”
事实是,您可以使用异步代码等待锁中的代码执行完毕,并在需要时等待它。这并不意味着锁中的代码必须是异步的。
这是一个例子:
class Program
{
static async Task Main(string[] args)
{
var rwl = new AsyncReadersWriterLock();
Console.WriteLine("* Example 1");
// run example 1
var result1 = Example1(rwl);
if (!result1.IsCompleted)
await result1;
Console.WriteLine("");
Console.WriteLine("* Example 2");
// run example 2
var result2 = Example2(rwl);
if (!result2.IsCompleted)
await result2;
}
private static async ValueTask Example1(AsyncReadersWriterLock rwl)
{
Console.WriteLine("Before calling UseReaderAsync");
var result = rwl.UseReaderAsync(async () =>
{
Console.WriteLine("Reader start");
await Task.Delay(1000);
Console.WriteLine("Reader end");
});
Console.WriteLine("After calling UseReaderAsync");
Console.WriteLine("");
if (!result.IsCompleted)
{
Console.WriteLine("result.IsCompleted == false, awaiting");
await result;
Console.WriteLine("await finished");
}
else
Console.WriteLine("result.IsCompleted == true, no await is used");
}
private static async ValueTask Example2(AsyncReadersWriterLock rwl)
{
Console.WriteLine("Before calling UseReaderAsync");
var result = rwl.UseReaderAsync(() =>
{
Console.WriteLine("Reader start");
// no async is used
//await Task.Delay(1000);
Console.WriteLine("Reader end");
});
Console.WriteLine("After calling UseReaderAsync");
Console.WriteLine("");
if (!result.IsCompleted)
{
Console.WriteLine("result.IsCompleted == false, awaiting");
await result;
Console.WriteLine("await finished");
}
else
Console.WriteLine("result.IsCompleted == true, no await is used");
}
}
导致:
* Example 1
Before calling UseReaderAsync
Reader start
After calling UseReaderAsync
result.IsCompleted == false, awaiting
Reader end
await finished
* Example 2
Before calling UseReaderAsync
Reader start
Reader end
After calling UseReaderAsync
result.IsCompleted == true
我还在努力。 (我对 github/creating nuget 包没有太多经验,所以欢迎任何想法)
包裹:nuget
来源:github