Requirements: It is now necessary to import data from multiple data sources into the target database, which is an example of a classic production and consumption application.
Directly on the code, look at the implementation:
//Initialize queue buffer size toidatacollection<list<t>> queue =NewQueuecollection<list<t>> ( -); //Open x Background task, read RABBITMQ queue information, insert queued information into buffer queue varCount =1; for(inti =0; I < count; i++) {Task.Factory.StartNew ()=NewProducer<list<t>> (queue). Start (NewRabbitsource<list<t>>(). Get)); } //open x background tasks, actively obtain database data, as a data producer, insert into the buffer queue, for(inti =0; I < count; i++) {Task.Factory.StartNew ()=NewProducer<list<t>> (queue). Start (NewDatabasesource<list<t>>(). Get)); } //open x background tasks, actively get read buffer queue, as a data message, the data inserted into the ES library, for(inti =0; I < count; i++) {Task.Factory.StartNew ()=NewCustomer<list<t>> (queue). Start (NewElastic (). Insert)); }
Queue we use a thread-safe concurrentqueue queue:
/// <summary> ///Buffer Queue///concurrentqueue thread safety, regardless of lock issue/// </summary> Public classQueuecollection<t>:idatacollection<t> { //Maximum Queue value Private int_maxsize; /// <summary> ///thread-safe queues/// </summary> PrivateConcurrentqueue<t>_queue; PublicQueuecollection (intmaxSize) { This. _maxsize =maxSize; _queue=NewConcurrentqueue<t>(); } Public BOOLispopwaiting () {return!_queue. Any (); } Public BOOLispushwaiting () {return This. _maxsize = =_queue. Count; } PublicT Pop () {t _obj=default(T); if(!_queue. IsEmpty) _queue. Trydequeue ( out_obj); return_obj; } Public voidPush (T t) {if( This. _maxsize >_queue. Count) {_queue. Enqueue (t); } } }
If we do not use this queue, we can replace it as long as the Idatacollection interface is satisfied:
Public InterfaceIdatacollection<t> { /// <summary> ///Inserting Data/// </summary> /// <param name= "T" ></param> voidPush (T t); /// <summary> ///Remove Data/// </summary> /// <returns></returns>T Pop (); /// <summary> ///whether to insert data waiting/// </summary> /// <returns></returns> BOOLispushwaiting (); /// <summary> ///whether to remove data waiting/// </summary> /// <returns></returns> BOOLispopwaiting (); }
Producers:
Public classProducer<t>: itransientdependency {Private intsleep; PrivateIdatacollection<t>Bufferqueue; PublicProducer (idatacollection<t>queue) {Sleep= the; Bufferqueue=queue; } Public voidStart (action<action<t>>Methodcall) { //QueueMethodcall ((bills) = { This. Enqueue (bills); }); } Private voidEnqueue (T t) {varIswaiting =true; while(iswaiting) {if(!bufferqueue.ispushwaiting ()) { This. Bufferqueue.push (t); Iswaiting=false; } Else { //producer Wait TimeThread.Sleep (Sleep); } } } }
Consumers:
/// <summary> ///Consumer/// </summary> Public classCustomer<t> { //Product Cache Queue PrivateIdatacollection<t>_queue; //Consumer Wait Time Private intSpead = the;//Consumer Wait Time PublicCustomer (idatacollection<t>queue) { This. _queue =queue; } Public voidStart (action<t>method) { while(true) { if(!_queue.ispopwaiting ()) {T box= This. _queue. Pop (); Method (box); } Else{thread.sleep (Spead); } } } }
The method delegate, also wrote a base class, actually the meaning is not big, only for the specification, prevents the method to be named arbitrarily.
Public Interface Idatasource<t> { void Get (action<t> func); }
Finally, in the Get method of DataSource, call Func.
Production consumption mode: Multithreading read-write queue Concurrentqueue