消息队列,Channel,无界队列,有界队列
- 因为队列的最大长度是 3,所以从 B 到 E 的消息被掉丢
- A 为什么没有丢掉,是因为刚写入的 A 消息被队列接收了,然后又写入了 B,C,D,E,F,G,H,然后 B 到 E 的消息被丢掉
D:\Code\ServiceModel.Grpc-master\Examples\SimpleChat\ChannelMsg>dotnet run
[写入] A: 1,写入成功: True
[写入] B: 2,写入成功: True
[写入] C: 3,写入成功: True
[写入] D: 4,写入成功: True
[写入] E: 5,写入成功: True
[写入] F: 6,写入成功: True
[写入] G: 7,写入成功: True
[写入] H: 8,写入成功: True
[读取] A: 1
[读取] F: 6
[读取] G: 7
[读取] H: 8
ChannelMsg\ChatConnection.cs
using System.Runtime.CompilerServices;
using System.Threading.Channels;
public class ChatConnection : IObserver<ChatMessage>
{
private const int MaxStuckMessages = 3;
private readonly Channel<ChatMessage> _channel;
public ChatConnection()
{
// - 构造函数,初始化 `_channel` 为有界队列,最多缓存 10 条消息。
// - `AllowSynchronousContinuations = false`:不允许同步执行回调,避免死锁。
// - `FullMode = BoundedChannelFullMode.DropOldest`:队列满时丢弃最早的消息。
// - `SingleReader = true`:只有一个消费者读取消息。
// - `SingleWriter = true`:只有一个生产者写入消息。
_channel = Channel.CreateBounded<ChatMessage>(
new BoundedChannelOptions(MaxStuckMessages)
{
AllowSynchronousContinuations = false,
FullMode = BoundedChannelFullMode.DropOldest,
SingleReader = true,
SingleWriter = true
}
);
}
public void OnCompleted() => _channel.Writer.TryComplete();
public void OnError(Exception error) => _channel.Writer.TryComplete(error);
public void OnNext(ChatMessage value)
{
bool written = _channel.Writer.TryWrite(value);
Console.WriteLine($"[写入] {value.Author}: {value.Content},写入成功: {written}");
}
public async IAsyncEnumerable<ChatMessage> AsEnumerable([EnumeratorCancellation] CancellationToken cancellationToken)
{
while (await _channel.Reader.WaitToReadAsync(cancellationToken))
{
while (_channel.Reader.TryRead(out var message))
{
// Console.WriteLine($"[读取] {message.Author}: {message.Content}");
yield return message;
}
}
}
}
ChannelMsg\ChatMessage.cs
public class ChatMessage
{
public required string Author { get; set; }
public required string Content { get; set; }
}
ChannelMsg\Program.cs
var conn = new ChatConnection();
var cts = new CancellationTokenSource();
// 消费者
var consumer = Task.Run(async () =>
{
await foreach (var msg in conn.AsEnumerable(cts.Token))
{
await Task.Delay(1000); // 模拟处理时间
Console.WriteLine($"[读取] {msg.Author}: {msg.Content}");
}
});
// 生产者
conn.OnNext(new ChatMessage { Author = "A", Content = "1" });
conn.OnNext(new ChatMessage { Author = "B", Content = "2" });
conn.OnNext(new ChatMessage { Author = "C", Content = "3" });
conn.OnNext(new ChatMessage { Author = "D", Content = "4" });
conn.OnNext(new ChatMessage { Author = "E", Content = "5" });
conn.OnNext(new ChatMessage { Author = "F", Content = "6" });
conn.OnNext(new ChatMessage { Author = "G", Content = "7" });
conn.OnNext(new ChatMessage { Author = "H", Content = "8" });
await Task.Delay(500);
conn.OnCompleted();
await consumer;