Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 您可能会看到什么<;T>;。ReadAny实现看起来像什么?_C#_Task Parallel Library_System.threading.channels - Fatal编程技术网

C# 您可能会看到什么<;T>;。ReadAny实现看起来像什么?

C# 您可能会看到什么<;T>;。ReadAny实现看起来像什么?,c#,task-parallel-library,system.threading.channels,C#,Task Parallel Library,System.threading.channels,BlockingCollection有一个方便的方法,允许您使用多个集合“我想要这些集合中的下一个项目” ChannelReader没有等价物,因此,如果您确实想将多个频道消耗到一个流中,比如说将接收到的项目逐个打印到控制台,该如何实现?快速路径很容易,但慢速路径相当棘手。下面的实现返回一个数组,其中包含从其中一个读卡器获取的值,以及输入数组中该读卡器的从零开始的索引 public static Task<(T Item, int Index)> ReadFromAnyAsync&l

BlockingCollection
有一个方便的方法,允许您使用多个集合“我想要这些集合中的下一个项目”


ChannelReader
没有等价物,因此,如果您确实想将多个频道消耗到一个流中,比如说将接收到的项目逐个打印到控制台,该如何实现?

快速路径很容易,但慢速路径相当棘手。下面的实现返回一个数组,其中包含从其中一个读卡器获取的值,以及输入数组中该读卡器的从零开始的索引

public static Task<(T Item, int Index)> ReadFromAnyAsync<T>(
    params ChannelReader<T>[] channelReaders) =>
    ReadFromAnyAsync(channelReaders, CancellationToken.None);

public static async Task<(T Item, int Index)> ReadFromAnyAsync<T>(
    ChannelReader<T>[] channelReaders,
    CancellationToken cancellationToken)
{
    cancellationToken.ThrowIfCancellationRequested();

    // Fast path
    for (int i = 0; i < channelReaders.Length; i++)
    {
        if (channelReaders[i].TryRead(out var item)) return (item, i);
    }

    // Slow path
    var locker = new object();
    int resultIndex = -1;
    T resultItem = default;
    while (true)
    {
        using (var cts = CancellationTokenSource
            .CreateLinkedTokenSource(cancellationToken, default))
        {
            bool availableAny = false;
            Task[] tasks = channelReaders
                .Select(async (reader, index) =>
                {
                    try
                    {
                        bool available = await reader.WaitToReadAsync(cts.Token)
                            .ConfigureAwait(false);
                        if (!available) return;
                    }
                    catch // Cancellation, or channel completed with exception
                    {
                        return;
                    }
                    availableAny = true;
                    lock (locker) // Take from one reader only
                    {
                        if (resultIndex == -1 && reader.TryRead(out var item))
                        {
                            resultIndex = index;
                            resultItem = item;
                            cts.Cancel();
                        }
                    }
                })
                .ToArray();

            await Task.WhenAll(tasks).ConfigureAwait(false);

            if (resultIndex != -1) return (resultItem, resultIndex);

            cancellationToken.ThrowIfCancellationRequested();

            if (!availableAny) throw new ChannelClosedException(
                "All channels are marked as completed.");
        }
    }
}
公共静态任务ReadFromAnyAsync(
参数ChannelReader[]channelReaders)=>
ReadFromAnyAsync(channelReaders,CancellationToken.None);
公共静态异步任务ReadFromAnyAsync(
频道阅读器[]频道阅读器,
取消令牌(取消令牌)
{
cancellationToken.ThrowIfCancellationRequested();
//快车道
for(int i=0;i
{
尝试
{
bool available=wait reader.WaitToReadAsync(cts.Token)
.配置等待(错误);
如果(!可用)返回;
}
捕获//取消,或通道已完成,但出现异常
{
返回;
}
有效性=真;
锁(储物柜)//仅从一个读卡器中取出
{
if(resultIndex==-1&&reader.TryRead(out变量项))
{
结果指数=指数;
结果m=项目;
cts.Cancel();
}
}
})
.ToArray();
等待任务.WhenAll(任务).配置等待(false);
if(resultIndex!=-1)返回(resultItem,resultIndex);
cancellationToken.ThrowIfCancellationRequested();
如果(!availableAny)抛出新的ChannelClosedException(
“所有通道均标记为已完成。”);
}
}
}

快速路径很容易,但慢速路径相当棘手。下面的实现返回一个数组,其中包含从其中一个读卡器获取的值,以及输入数组中该读卡器的从零开始的索引

public static Task<(T Item, int Index)> ReadFromAnyAsync<T>(
    params ChannelReader<T>[] channelReaders) =>
    ReadFromAnyAsync(channelReaders, CancellationToken.None);

public static async Task<(T Item, int Index)> ReadFromAnyAsync<T>(
    ChannelReader<T>[] channelReaders,
    CancellationToken cancellationToken)
{
    cancellationToken.ThrowIfCancellationRequested();

    // Fast path
    for (int i = 0; i < channelReaders.Length; i++)
    {
        if (channelReaders[i].TryRead(out var item)) return (item, i);
    }

    // Slow path
    var locker = new object();
    int resultIndex = -1;
    T resultItem = default;
    while (true)
    {
        using (var cts = CancellationTokenSource
            .CreateLinkedTokenSource(cancellationToken, default))
        {
            bool availableAny = false;
            Task[] tasks = channelReaders
                .Select(async (reader, index) =>
                {
                    try
                    {
                        bool available = await reader.WaitToReadAsync(cts.Token)
                            .ConfigureAwait(false);
                        if (!available) return;
                    }
                    catch // Cancellation, or channel completed with exception
                    {
                        return;
                    }
                    availableAny = true;
                    lock (locker) // Take from one reader only
                    {
                        if (resultIndex == -1 && reader.TryRead(out var item))
                        {
                            resultIndex = index;
                            resultItem = item;
                            cts.Cancel();
                        }
                    }
                })
                .ToArray();

            await Task.WhenAll(tasks).ConfigureAwait(false);

            if (resultIndex != -1) return (resultItem, resultIndex);

            cancellationToken.ThrowIfCancellationRequested();

            if (!availableAny) throw new ChannelClosedException(
                "All channels are marked as completed.");
        }
    }
}
公共静态任务ReadFromAnyAsync(
参数ChannelReader[]channelReaders)=>
ReadFromAnyAsync(channelReaders,CancellationToken.None);
公共静态异步任务ReadFromAnyAsync(
频道阅读器[]频道阅读器,
取消令牌(取消令牌)
{
cancellationToken.ThrowIfCancellationRequested();
//快车道
for(int i=0;i
{
尝试
{
bool available=wait reader.WaitToReadAsync(cts.Token)
.配置等待(错误);
如果(!可用)返回;
}
捕获//取消,或通道已完成,但出现异常
{
返回;
}
有效性=真;
锁(储物柜)//仅从一个读卡器中取出
{
if(resultIndex==-1&&reader.TryRead(out变量项))
{
结果指数=指数;
结果m=项目;
cts.Cancel();
}
}
})
.ToArray();
等待任务.WhenAll(任务).配置等待(false);
if(resultIndex!=-1)返回(resultItem,resultIndex);
cancellationToken.ThrowIfCancellationRequested();
如果(!availableAny)抛出新的ChannelClosedException(
“所有通道均标记为已完成。”);
}
}
}

也许你可以从多个制作人(如频道)向单个
BlockingCollection
中添加项目,并使用单个循环消费。我想用
频道
来取代
BlockingCollection
,但相同的想法是,多个
频道阅读器
为另一个
频道编写器
,然后被另一个
通道读取器
使用,可以工作。不过它看起来很笨重。也许你可以从多个制作人(如频道)向单个
BlockingCollection
添加项目,并通过单个循环使用它。我会寻求使用
Channel
来取代
BlockingCollection
,但同样的想法,多个
频道阅读器
向另一个
频道阅读器
提供信息,然后被另一个
频道阅读器
使用,这些阅读器可以工作。不过它看起来很笨重。