需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子。

直接上代码,看下实现:

            // 初始化列队缓冲区 队列大小为100
IDataCollection<List<T>> queue = new QueueCollection<List<T>>(); //开启X个后台任务,读取RabbitMQ队列信息, 把列队信息插入缓冲区队列
var count = ;
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Producer<List<T>>(queue).Start(new RabbitSource<List<T>>().Get));
} //开启X个后台任务,主动获取数据库数据,作为数据生产者,插入到缓冲区队列,
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Producer<List<T>>(queue).Start(new DatabaseSource<List<T>>().Get));
} //开启X个后台任务,主动获取读取缓冲区列队,作为数据消息者,把数据插入到ES库,
for (int i = ; i < count; i++)
{
Task.Factory.StartNew(() => new Customer<List<T>>(queue).Start(new Elastic().Insert));
}

队列我们采用线程安全的ConcurrentQueue队列:

/// <summary>
/// 缓冲区队列
/// ConcurrentQueue线程安全,不用考虑锁的问题
/// </summary>
public class QueueCollection<T> :IDataCollection<T>
{
//队列最大值
private int _maxSize; /// <summary>
/// 线程安全的队列
/// </summary>
private ConcurrentQueue<T> _queue; public QueueCollection(int maxSize)
{
this._maxSize = maxSize;
_queue = new ConcurrentQueue<T>();
} public bool isPopWaiting()
{
return !_queue.Any();
} public bool isPushWaiting()
{
return this._maxSize == _queue.Count;
} public T Pop()
{
T _obj = default(T);
if (!_queue.IsEmpty)
_queue.TryDequeue(out _obj); return _obj;
} public void Push(T t)
{
if (this._maxSize > _queue.Count)
{
_queue.Enqueue(t);
}
}
}

如果我们不使用这个队列,只要满足IDataCollection接口,也可以进行替换:

public interface IDataCollection<T>
{
/// <summary>
/// 插入数据
/// </summary>
/// <param name="t"></param>
void Push(T t); /// <summary>
/// 取出数据
/// </summary>
/// <returns></returns>
T Pop(); /// <summary>
/// 是否插入数据等待
/// </summary>
/// <returns></returns>
bool isPushWaiting(); /// <summary>
/// 是否取出数据等待
/// </summary>
/// <returns></returns>
bool isPopWaiting(); }

生产者:

 public class Producer<T> : ITransientDependency
{
private int sleep; private IDataCollection<T> bufferQueue; public Producer(IDataCollection<T> queue)
{
sleep = ;
bufferQueue = queue;
} public void Start(Action<Action<T>> methodCall)
{
//入队
methodCall((bills) =>
{
this.Enqueue(bills);
});
} private void Enqueue(T t)
{
var isWaiting = true; while (isWaiting)
{
if (!bufferQueue.isPushWaiting())
{
this.bufferQueue.Push(t);
isWaiting = false;
}
else
{
//生产者等待时间
Thread.Sleep(sleep);
}
}
}
}

消费者:

/// <summary>
/// 消费者
/// </summary>
public class Customer<T>
{
//产品缓存队列
private IDataCollection<T> _queue; //消费者等待时间
private int Spead = ;//消费者等待时间 public Customer(IDataCollection<T> queue)
{
this._queue = queue;
} public void Start(Action<T> method)
{
while (true)
{
if (!_queue.isPopWaiting())
{
T box = this._queue.Pop(); method(box);
}
else
{
Thread.Sleep(Spead);
}
}
}
}

方法委托,也写了个基类,其实意义并不大,只是为了规范, 防止方法命名随意起。

    public interface IDataSource<T>
{
void Get(Action<T> func);
}

最后,在DataSource的get方法中,调用 func即可。

生产消费模式:多线程读写队列ConcurrentQueue的更多相关文章

  1. 使用C#的泛型队列Queue实现生产消费模式

    本篇体验使用C#的泛型队列Queue<T>实现生产消费模式. 如果把生产消费想像成自动流水生产线的话,生产就是流水线的物料,消费就是某种设备对物料进行加工的行为,流水线就是队列. 现在,要 ...

  2. 使用Condition实现多线程之间调用(生产消费模式)

    一,object 类的wait(),notify()和notifyAll() Java 线程类也是一个object 类,它的实例都继承自java.lang.Thread 或其子类.wait(),not ...

  3. Java的多线程实现生产/消费模式

    Java的多线程实现生产/消费模式 在Java的多线程中,我们经常使用某个Java对象的wait(),notify()以及notifyAll() 方法实现多线程的通讯,今天就使用Java的多线程实现生 ...

  4. 异步简析之BlockingCollection实现生产消费模式

    目前市面上有诸多的产品实现队列功能,比如Redis.MemCache等... 其实c#中也有一个基础的集合类专门用来实现生产/消费模式 (生产模式还是建议使用Redis等产品) 下面是官方的一些资料和 ...

  5. SQLite多线程读写实践及常见问题总结

    多线程读写 SQLite实质上是将数据写入一个文件,通常情况下,在应用的包名下面都能找到xxx.db的文件,拥有root权限的手机,可以通过adb shell,看到data/data/packagen ...

  6. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  7. JAVA多线程读写文件范例

    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址.如果有知情者,烦请帖出地址,我在此文上加入 ...

  8. c# 高效的线程安全队列ConcurrentQueue

    c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...

  9. 为什么多线程读写 shared_ptr 要加锁?

    https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...

随机推荐

  1. 剑指Offer——构建乘积数组

    题目描述: 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]. ...

  2. uchome client.php

    uchome 主要使用了php的call_user_func()函数,在uc_clinet/client.php中,一般指向uc_api_mysql,而 uc_api_mysql()函数 则负责分发到 ...

  3. NSUserDefaults保存对象数组报错

    在使用NSUserDefaults的时候插入数据有时候会报以下错误:Attempt to set a non-property-list objec 这种错误的原因是插入了不识别的数据类型,NSUse ...

  4. HTML5开源RPG游戏引擎lufylegendRPG 1.0.0发布

    经历了几个月的改进,终于发布1.0.0版了.虽然引擎依然存在漏洞,但是比起上次更新还是要好多了.在这里不得不感谢各位网友的大力支持. 首先为引擎做一个开场白吧,也好让大家了解一下它: lufylege ...

  5. FB05付款清帐Function

    函数组:FIPI-->内部FI过帐接口1.CALL FUNCTION 'POSTING_INTERFACE_START'. -->Initial information for inter ...

  6. 文件传输(xmodem协议)

    https://www.menie.org/georges/embedded/ 需要移植如下两个基础的硬件读写函数 int _inbyte(unsigned short timeout); void ...

  7. 别真以为JavaScript中func.call/apply/bind是万能的!

    自从学会call/apply/bind这三个方法后我就各种场合各种使用各种得心应手至今还没踩过什么坑,怎么用?说直白点就是我自己的对象没有某个方法但别人有,我就可以通过call/apply/bind去 ...

  8. Spring第八发—自动装配及让Spring自动扫描和管理Bean

    依赖注入–自动装配依赖对象(了解即可) 对于自动装配,大家了解一下就可以了,实在不推荐大家使用.例子: byName:按名称装配,可以根据属性的名称,在容器中寻找跟该属性名相同的bean,如果没有找到 ...

  9. HomeBrew的安装详细步骤

    1)终端输入:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master ...

  10. C++必知必会

    C++ Common knowledge Essential Intermediate Programming C++必知必会 [美] StephenC.Dewhurst 著  荣耀 译  人民邮电出 ...