Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.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/6/multithreading/4.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# 如何正确使用ConcurrentQueue中的Chunck_C#_Multithreading_Task Parallel Library_Producer Consumer_Tpl Dataflow - Fatal编程技术网

C# 如何正确使用ConcurrentQueue中的Chunck

C# 如何正确使用ConcurrentQueue中的Chunck,c#,multithreading,task-parallel-library,producer-consumer,tpl-dataflow,C#,Multithreading,Task Parallel Library,Producer Consumer,Tpl Dataflow,我需要实现一个可以从多个线程填充的请求队列。当此队列大于1000个已完成的请求时,应将此请求存储到数据库中。以下是我的实现: public class RequestQueue { private static BlockingCollection<VerificationRequest> _queue = new BlockingCollection<VerificationRequest>(); private static ConcurrentQue

我需要实现一个可以从多个线程填充的请求队列。当此队列大于1000个已完成的请求时,应将此请求存储到数据库中。以下是我的实现:

public class RequestQueue
{
    private static BlockingCollection<VerificationRequest> _queue = new BlockingCollection<VerificationRequest>();
    private static ConcurrentQueue<VerificationRequest> _storageQueue = new ConcurrentQueue<VerificationRequest>();

    private static volatile bool isLoading = false;
    private static object _lock = new object();

    public static void Launch()
    {
        Task.Factory.StartNew(execute);
    }

    public static void Add(VerificationRequest request)
    {
        _queue.Add(request);
    }

    public static void AddRange(List<VerificationRequest> requests)
    {
        Parallel.ForEach(requests, new ParallelOptions() {MaxDegreeOfParallelism = 3},
            (request) => { _queue.Add(request); });
    }


    private static void execute()
    {
        Parallel.ForEach(_queue.GetConsumingEnumerable(), new ParallelOptions {MaxDegreeOfParallelism = 5}, EnqueueSaveRequest );
    }

    private static void EnqueueSaveRequest(VerificationRequest request)
    {
        _storageQueue.Enqueue( new RequestExecuter().ExecuteVerificationRequest( request ) );
        if (_storageQueue.Count > 1000 && !isLoading)
        {
            lock ( _lock )
            {
                if ( _storageQueue.Count > 1000 && !isLoading )
                {
                    isLoading = true;

                    var requestChunck = new List<VerificationRequest>();
                    VerificationRequest req;
                    for (var i = 0; i < 1000; i++)
                    {
                        if( _storageQueue.TryDequeue(out req))
                            requestChunck.Add(req);
                    }
                    new VerificationRequestRepository().InsertRange(requestChunck);

                    isLoading = false;
                }
            }
        }            
    }
}
公共类请求队列
{
私有静态BlockingCollection_queue=新BlockingCollection();
私有静态ConcurrentQueue_storageQueue=新ConcurrentQueue();
私有静态易失性bool isLoading=false;
私有静态对象_lock=新对象();
公共静态无效启动()
{
Task.Factory.StartNew(执行);
}
公共静态无效添加(验证请求)
{
_添加(请求);
}
公共静态void AddRange(列表请求)
{
ForEach(请求,新的ParallelOptions(){MaxDegreeOfParallelism=3},
(请求)=>{u queue.Add(请求);});
}
私有静态void execute()
{
ForEach(_queue.getconsumineGenumerable(),新的并行选项{MaxDegreeOfParallelism=5},EnqueueSaveRequest);
}
私有静态void排队保存请求(VerificationRequest请求)
{
_entqueue(newrequestexecuter().executeReferationRequest(request));
如果(_storageQueue.Count>1000&&!isLoading)
{
锁
{
如果(_storageQueue.Count>1000&&!isLoading)
{
isLoading=true;
var requestChunck=新列表();
验证请求请求;
对于(变量i=0;i<1000;i++)
{
if(_storageQueue.TryDequeue(输出请求))
requestChunck.Add(请求);
}
新的VerificationRequestRepository().InsertRange(requestChunck);
isLoading=false;
}
}
}            
}
}

有没有办法在没有锁定和isLoading的情况下实现这一点?

最简单的方法就是使用库中的块。乙二醇

var batchBlock = new BatchBlock<VerificationRequest>(1000);
var exportBlock = new ActionBlock<VerificationRequest[]>(records=>{
               new VerificationRequestRepository().InsertRange(records);
};

batchBlock.LinkTo(exportBlock , new DataflowLinkOptions { PropagateCompletion = true });
完成工作后,可以通过调用
batchBlock.Complete()关闭整个管道并清除任何剩余消息并等待最后一个块完成:

batchBlock.Complete();
await exportBlock.Completion;
将多达1000条记录批处理为1000个项的数组,并将它们传递到下一个块。默认情况下,一个任务只使用1个任务,因此它是线程安全的。您可以使用存储库的现有实例,而不必担心跨线程访问:

var repository=new VerificationRequestRepository();
var exportBlock = new ActionBlock<VerificationRequest[]>(records=>{
               repository.InsertRange(records);
};
var repository=new-VerificationRequestRepository();
var exportBlock=新操作块(记录=>{
repository.InsertRange(记录);
};
几乎所有的块都有一个并发输入缓冲区。每个块都在其自己的TPL任务上运行,因此每个步骤都彼此并发运行。这意味着您可以“免费”获得异步执行,如果您有多个链接的步骤,这一点可能很重要,例如,您可以使用一个来修改流经管道的消息


我使用这些管道来创建调用外部服务的管道、解析响应、生成最终记录、批处理它们并将它们发送到使用SqlBulkCopy的块的数据库。

为什么不使用lock?我的意思是,在这种情况下,它似乎不会以任何方式影响性能。我同意,但可能有更好的方法。而且我不是确保我正确地使用isLoading实现锁定为什么您甚至需要
isLoading
?如果您只是删除它,会有什么变化?为了防止在我们已经开始存储TPL数据流时等待锁定:
var repository=new VerificationRequestRepository();
var exportBlock = new ActionBlock<VerificationRequest[]>(records=>{
               repository.InsertRange(records);
};