定时器每1
分钟接收一次文件,
接收后写入文件队列,
然后唤醒文件线程
文件线程
查看文件队列,
有文件就一直处理文件,
文件队列
为空就wait()
处理文件
分为subscribe
和subscription-update
两种情况
处理文件,
即唤醒处理数据线程管理器,
处理数据线程管理器
再把切割(100k
一个小文件)
的文件按顺序分别唤醒10
个
处理数据线程
去处理
如果是subscribe,
由于数据全部都是insert,
所以可以10
个线程并行处理的时候,
可以不考虑SQL
数据的顺序处理,
直接处理到数据库就行了
如果是subscription-update,
由于数据可以先更新为a,
再更新为b,
所以SQL
的处理必须按顺序,
即唤醒处理数据线程管理器,
处理数据线程管理器第一
寻找可用的线程(
即该线程目前处于wait
状态)
第二
寻找可用的
SQL
临时存储队列(
共分配了10
个二维数组),
两者都找到可用,
则指定该线程处理当前切割后的小文件,
并将SQL
语句存后
SQL
临时存储队列,
同时通知
SQL
执行线程
哪个二维数组已经有完整数据了
SQL
执行线程
按顺序查看是否有已经有完整数据的二维数组,
有的就进行处理
各线程什么时候wait
和notify:
定时器
接收完文件,
就notify
文件线程
文件线程
发现文件队列为空,
则wait
文件之间(
非切割的小文件之间)
处理不可并行,
所以文件线程只采用一个,
处理数据线程管理器
也只能采用一个,
并给后者加synchronized
同步(
这样如果文件线程遇到两个文件,
第二次notify
管理器后,
会阻塞,
直到第一个文件处理完,
这样是对的,
但如果此时被定时器notify
会出乱?
在管理器上加一正在处理标志,
不凭本身线程状态来判断或阻塞,
这样一个时刻处理数据线程管理器只会处理一个文件)
依上方法,
处理数据线程管理器
执行完自己wait
同时,
处理数据线程管理器
处理完后立即notify
文件线程,
这样对有积压多个文件的时候有好处,
不必等待定时器notify
当文件线程发现文件,
并正在处理标志为否,
则notify
处理数据线程管理器
SQL
执行线程
有按顺序的二维数组,
则一直按顺序处理,
没有就wait()
每次处理数据线程处理完就notify
SQL
执行线程(
适用于subscription-update
)
通过以上 切割文件 和 多线程 的方案, 同时连接池保持10个数据库连接, 使速度提高了6倍左右, 在本地测试时一分钟处理4M的数据
再优化mysql参数, 又提高了8倍左右, 核心的是innodb_flush_log_at_trx_commit, 是一秒钟写一次事务日志, 还是每个SQL写一次事务日志(如果一秒执行400个SQL,后者模式需要1秒写400次磁盘, 很影响效率), 现在在本地测试(双核5000+, 2G内存)达到一分钟处理35M的数据, CPU平均占用95%