我正在开发一个.net Core3.0 web应用程序,并决定在单例服务中使用System.Threading.Channels。我的作用域请求服务的顶层注入了这个单例来访问它的通道。
我决定使用此模式将请求(为其他连接的客户端生成实时更新)与这些更新的执行解耦。
在一个对象中实现一个通道有很多例子。
有人能告诉我在我的单例中使用多个通道是否可行/可取吗?
创建多个通道并在创建单例时“启动”它们时,我还没有遇到任何问题。我只是还没有达到一个点,我可以测试多个客户端请求在单例上的不同通道,看看它是否工作良好。(或者根本没有?... )
我使用多个通道的主要动机是希望单例根据通道中项的类型做不同的事情。
public class MyChannelSingleton
{
public Channel<MyType> TypeOneChannel = Channel.CreateUnbounded<MyType>();
public Channel<MyOtherType> TypeTwoChannel = Channel.CreateUnbounded<MyOtherType>();
public MyChannelSingleton()
{
StartChannels();
}
private void StartChannels()
{
// discarded async tasks due to calling in ctor
_ = StartTypeOneChannel();
_ = StartTypeTwoChannel();
}
private async Task StartTypeOneChannel()
{
var reader = TypeOneChannel.Reader;
while (await reader.WaitToReadAsync())
{
if (reader.TryRead(out MyType item))
{
// item is sucessfully read from channel
}
}
}
private async Task StartTypeTwoChannel()
{
var reader = TypeTwoChannel.Reader;
while (await reader.WaitToReadAsync())
{
if (reader.TryRead(out MyOtherType item))
{
// item is sucessfully read from channel
}
}
}
}我还希望永远不会“完成”通道,并让它们在应用程序的生命周期中可用。
发布于 2019-11-12 04:57:52
Channel只是一个线程安全的异步队列。它本身不做任何处理,它只是一个被动的内存中的FIFO存储。你可以想要多少就有多少。
您可以利用Channel分别公开Reader和Writer这一事实,将您的类的客户端的访问限制为它们所需的最低功能。换句话说,您可以考虑公开ChannelWriter<T>或ChannelReader<T>类型的属性,而不是公开Channel<T>类型的属性。
此外,创建无界通道时应谨慎操作。一个误用的通道很容易使您的应用程序成为OutOfMemoryException的牺牲品。
公开ChannelReader<T>类型的属性的另一种方法是公开IAsyncEnumerable。
发布于 2019-11-12 04:55:30
不幸的是,我可以使用not find the sourcecode。而调用Documentation sparse可能是轻描淡写的。所以我充其量只能告诉你“如果这是我的课,我会怎么做”。
在内存中有多个通道的大问题-特别是无限制的-将是导致早期OOM的内存碎片。实际上,即使只有一个是无界的,一个大问题就是必须增加集合。List<T>只不过是T[]的包装器,具有一些自动增长支持。无界列表的另一个问题是迟早会run out of indexes。
我该如何解决这个问题?一个Linked List。在大约90%的情况下,链表是我最后考虑的集合。剩下的10%是队列和类似队列的构造。通道看起来非常像一个队列。在这10%的情况下,在9%的情况下,我只会使用队列实现所做的任何事情。这是剩下的1%。
对于随机访问,链表是最糟糕的集合。对于队列,这是可行的。但是在.NET中避免与OOM相关的碎片?将增长成本降至最低?为了绕过硬数组的限制?这里的链表是绝对无与伦比的。
如果它没有做到这一点呢?这应该是可行的,使您自己的版本的频道做到了这一点,并只是取代它。
https://stackoverflow.com/questions/58807485
复制相似问题