Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.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#在asp.net核心托管服务使用者中使用多个并行任务处理IAsyncEnumerable项_C#_Asynchronous_Stream_Producer Consumer_Asp.net Core Hosted Services - Fatal编程技术网

C#在asp.net核心托管服务使用者中使用多个并行任务处理IAsyncEnumerable项

C#在asp.net核心托管服务使用者中使用多个并行任务处理IAsyncEnumerable项,c#,asynchronous,stream,producer-consumer,asp.net-core-hosted-services,C#,Asynchronous,Stream,Producer Consumer,Asp.net Core Hosted Services,我正在使用托管服务在asp.net核心应用程序中实现生产者-消费者。我能够让它工作到消费者正在同步处理来自\u recordProcessingChannel.ReadAllAsync()的项目的程度 我正在尝试将\u recordProcessingChannel.ReadAllAsync()的结果拆分为几个并行任务。 例如:我从频道中读取了10000个项目,我想将这项工作分成4个独立的任务,每个ICMService处理2500个项目 消费者: await foreach (var recor

我正在使用托管服务在asp.net核心应用程序中实现生产者-消费者。我能够让它工作到消费者正在同步处理来自
\u recordProcessingChannel.ReadAllAsync()
的项目的程度

我正在尝试将
\u recordProcessingChannel.ReadAllAsync()
的结果拆分为几个并行任务。 例如:我从频道中读取了10000个项目,我想将这项工作分成4个独立的任务,每个ICMService处理2500个项目

消费者:

await foreach (var record in _recordProcessingChannel.ReadAllAsync())
{

    using var scope = _serviceProvider.CreateScope();
    var processor = scope.ServiceProvider.GetRequiredService<ICMService>();

    processor.UploadRecord(record);
                
}
wait foreach(在_recordProcessingChannel.ReadAllAsync()中的var记录)
{
使用var scope=_serviceProvider.CreateScope();
var processor=scope.ServiceProvider.GetRequiredService();
处理器。上传记录(记录);
}
读者:

public IAsyncEnumerable<RecordData> ReadAllAsync(CancellationToken ct = default) => _channel.Reader.ReadAllAsync(ct);
public IAsyncEnumerable ReadAllAsync(CancellationToken ct=default)=>\u channel.Reader.ReadAllAsync(ct);

提前感谢您提供的任何帮助

您可以启动所需数量的处理任务,并使用来排队工作。大概是这样的:

// my dummy async enumerable
public async IAsyncEnumerable<int> ReadAllAsync()
{
    for (int i = 0; i < 3; i++)
    {
        yield return i*3 + 1;
        yield return i*3 + 2;
        yield return i*3 + 3;
        await Task.Delay(200);
    }
    yield return 777;
}
var collection = new BlockingCollection<int>();
// start "processors"
var tasks = Enumerable.Range(0, 4)
    .Select(i => 
        Task.Run(() =>
        {
            while (!collection.IsCompleted)
            {           
                int? data = null;
                try
                {
                    data = collection.Take();
                }
                catch (InvalidOperationException) { }

                if (data != null)
                {
                    // simulate processing 
                    Thread.Sleep(400);
                    Console.WriteLine(data.Value);
                }
            }
            Console.WriteLine("No more items to take.");
        }))
    .ToArray();

await foreach (var record in ReadAllAsync())
{
    collection.Add(record);
}
collection.CompleteAdding(); // signal that enqueuing has finished

await Task.WhenAll(tasks);

您是希望本地缓冲10000个项目,并在它们全部被接收后将它们分成4个区块,并将每个区块发送到单独的ICMService进行处理,还是希望在接收到每个单独的项目时将其发送到ICMService?在第二种情况下,您希望交替使用ICMService,以便向每个ICMService发送2500个项目,还是执行负载平衡并向响应更快的ICMService的?第一个选项发送更多项目。随着用户发布他们的请求,消息包将进入通道,所以一次将达到10000条,一段时间后再达到8000条,然后再达到12000条。我想对这些块进行负载平衡,因此当10000个服务实例出现时,每个服务实例将处理~2500个,然后当8000个服务实例出现时,每个服务实例将处理~2000个,以此类推。批量大小的标准是一次10000、另一次8000和另一次12000?是否要根据经过的时间间隔而不是大小触发批处理?也可以向外部库添加依赖项,特别是向外部库添加依赖项吗?谢谢,这非常有帮助。@KrisBog很高兴它有帮助!
var collection = new ConcurrentQueue<int>();
var semaphore = new SemaphoreSlim(0, 4);
var cts = new CancellationTokenSource(); // to signal that queueing is completed
var tasks = Enumerable.Range(0, 4)
    .Select(i => 
        Task.Run(async () =>
        {
            while (true)
            {
                if (cts.Token.IsCancellationRequested && !collection.Any())
                {
                    Console.WriteLine("No more items to take.");
                    break;
                }
                else if (!cts.Token.IsCancellationRequested)
                {
                    try
                    {
                        await semaphore.WaitAsync(cts.Token);
                    }
                    catch (OperationCanceledException)
                    {
                        //ignore
                    }
                }

                if(collection.TryDequeue(out var data))
                {
                    //simulate work
                    Thread.Sleep(400);
                    Console.WriteLine(data);
                }                   
            }
        }))
    .ToArray();

await foreach (var record in ReadAllAsync())
{
    collection.Enqueue(record);
    semaphore.Release();
}
cts.Cancel(); // addition completed.
await Task.WhenAll(tasks);
Console.WriteLine("end");