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

直接上代码,看下实现:

            // 初始化列队缓冲区 队列大小为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. Buy the souvenirs---hdu2126(01背包输出方案数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 有n个物品每个物品的价格是v[i],现在有m元钱问最多买多少种物品,并求出有多少种选择方法: 如 ...

  2. Drainage Ditches---hdu1532(最大流, 模板)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 最大流模板题: EK:(复杂度为n*m*m); #include<stdio.h> ...

  3. golang几种post方式

    用golang进行http请求类型多了,总结备忘一下. 1.普通的post\get请求 var r http.Request r.ParseForm() r.Form.Add("uuid&q ...

  4. Ubutun使用记录——语系错误(转)

    add by zhj: 对原文有修改,原文是在创建用户时出现的问题,而我是在使用psql时出现的, 但问题是相同的. 原文:http://www.douban.com/note/362250557/ ...

  5. ubuntu配置Python-Django Nginx+uwsgi 安装配置

    安装Nginx sudo apt-get install nginx ubantu安装完Nginx后,文件结构大致为: 所有的配置文件都在 /etc/nginx下: 启动程序文件在 /usr/sbin ...

  6. 大量高清文字版PDF编程书籍下载

    下载地址 :http://zhaojucai.com/download.html 文件夹: 数学之美(第二版) Java编程思想(第4版) 图灵程序设计丛书:Python基础教程(第2版)(修订版) ...

  7. 2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascrip版)

    一,原理介绍 这回有点复杂,不过看懂了还是很好理解的.当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我. 我们首先来建立一个以圆心为原点的坐标系: 然后要检 ...

  8. Linux PHP7的openssl扩展安装

    Linux环境下使用PHPmailer发送邮件时,出现如下错误: SMTP -> ERROR: Failed to connect to server: Unable to find the s ...

  9. 重新编写equals()方法,hashCode()方法,以及toString(),提供自定义的相等标准,以及自描述方法

    下面给出一个实例,重新编写equals()方法,提供自定义的相等标准 public class PersonTest { public static void main(String[] args) ...

  10. Python中的None与Null(空字符)的区别

    参考自 Python中的None与空字符(NULL)的区别 - CSDN博客 http://blog.csdn.net/crisschan/article/details/70312764 首先了解p ...