问题描述
比如,有一个数据表(可以理解为队列不?)中有5000条未完成数据,每条数据需要进行复杂的计算、处理、写入文本文件后才能标记为完成。现在是单台机器按先进先出的原则逐条处理。领导觉得太慢了,想加几台机器同时处理【数据表是同一个】。我现在想法是,假如有两台机器,每台机器每五分钟读取一些待处理数据,然后处理。A机器处理ID为单号的,B机器处理ID为双号的。大家觉得可行吗?MSsql不能select单双数ID吧。。。我知道这是一个很笨的方法,期待高手们能有更好的方法
解决方案
解决方案二:
所谓的多线程就是开启多个线程同时执行某个单项任务,最终完成某个事情的过程。但是并不是开启的线程数越多越好,到达一个临界点之后,效率反而会降低。你首先要做的就是将你的任务进行分解(比如你有5000条数据,开启5个线程,线程1处理1-1000条数据,线程2处理1001-2000条数据,以此类推),然后让线程单独执行各自的操作,最后共同完成这项任务。
解决方案三:
首先,假设要处理5000个并发任务,可以使用这样的写法。例如我们准备一个“测试条件”集合,随便用顺序号来表示varcondition=Enumerable.Range(0,5000).ToList();
假设每当接受一个输入编号,进行一项计算,这样模拟staticRandomrnd=newRandom();privatestaticboolsolve(intx){returnrnd.Next(2)+x==0;}
那么要并发执行这5000千个solve方法(输入的x各不相同),则应该这样写varresult=(fromxincondition.AsParallel()selectsolve(x)).ToList();
这就是并发执行这些任务。对于你的程序来说,如果在一台机器上并发处理这5000条记录,那么就可以用condition来一次读取出来5000条数据,用solve来处理记录(单个记录对应的实体对象代替这里的x变量),最后得到每条记录处理的结果集合,返回统计。对于plinq来说,它使用了.net的系统线程池,因此可以根据你的机器的使用情况来自动优化并发数量。所以不用担心、也不用手动规定什么并发数据量。当然如果你想限制最多用30个并发线程,也可以手动规定,例如varresult=(fromxincondition.AsParallel().WithDegreeOfParallelism(30)selectsolve(x)).ToList();
但是通常不必这样多此一举。
解决方案四:
对于你分布式处理问题,由于比较简单,我们用基本的分布式原则(而且不考虑内外网之分)来设计,不用纠结什么高大上的什么开源框架(.net中也没有类似PLinq那样的现成的框架)。那么可以这样设计:你可以为你的数据库表加上一个“状态”字段,至少有三种状态值:1.未处理。2.正在处理。3.处理完毕。然后假设你有n台机器(千万比要想当然地以为固定为5台机器或者2台机器,不然反而造成资源浪费),每台机器都访问这个数据库来“抢夺”一个处于“未处理”状态的记录、并且在同一个事务中把它变为“正在处理”状态。这个操作肯定很快,连查询带改变状态(在同一个事务中)然后读取记录,这三项功能也就几毫秒就做完了。然后就对记录进行你的费时的处理,然后把处理结果送到统一规定的位置,然后处理下一条数据。这跟你的“A、B”机的说法类似,区别是,这里不假设只能有2台机器。并且注意数据库操作尽可能限制在4、5毫秒之内。而且也不是什么“每隔5分钟处理一批数据”。应该是收到请求既启动。例如其发布的网页只要被人访问一下,例如http://192.268.1.203:81/proc1/default.ashx就触发其启动。这样,当年任何地方知道有数据产生的时候,改变这里的ip来通知各个机器(机器的ip地址可以配置好)开始启动操作就行了。根据机器的处理速度的快慢、以及数据本身的不同,可能A机器处理了2100条记录,B机器处理了1850条记录,C机器处理了1050条记录,这都是可能的。不要想当然地以为需要固定指定“几台机器,每台机器分别处理哪些条记录”。看似简单但是死板的设计会产生很差的性能。
解决方案五:
引用2楼sp1234的回复:
首先,假设要处理5000个并发任务,可以使用这样的写法。例如我们准备一个“测试条件”集合,随便用顺序号来表示varcondition=Enumerable.Range(0,5000).ToList();假设每当接受一个输入编号,进行一项计算,这样模拟staticRandomrnd=newRandom();privatestaticboolsolve(intx){returnrnd.Next(2)+x==0;}
那么要并发执行这5000千个solve方法(输入的x各不相同),则应该这样写varresult=(fromxincondition.AsParallel()selectsolve(x)).ToList();
这就是并发执行这些任务。对于你的程序来说,如果在一台机器上并发处理这5000条记录,那么就可以用condition来一次读取出来5000条数据,用solve来处理记录(单个记录对应的实体对象代替这里的x变量),最后得到每条记录处理的结果集合,返回统计。对于plinq来说,它使用了.net的系统线程池,因此可以根据你的机器的使用情况来自动优化并发数量。所以不用担心、也不用手动规定什么并发数据量。当然如果你想限制最多用30个并发线程,也可以手动规定,例如varresult=(fromxincondition.AsParallel().WithDegreeOfParallelism(30)selectsolve(x)).ToList();
但是通常不必这样多此一举。
大神可能没有明白简单的说,我现在有一个队列表,其中是有很多条任务,任务队列不断的增加,程序定期访问这个表,得到未处理的任务进行处理,然后处理完成做标记。如果现在有两台服务器,我可以一台处理单数ID,另一台处理偶数ID的任务。我希望能有更好的方法
解决方案六:
关键的问题在于,数据在公网,而工作的几台机器在内网。这样就没有办法通知它们起来工作,除了让它们定时来轮询
解决方案七:
实际上,所谓分布式计算,非常简单。上面的很简单模型已经有了完整的框架雏形,只不过实现方法不同而已。1.首先需要有一个client负责将任务倒入到系统中,然后通知一个master机器处理这一批次的任务。2.然后master通知所有的worker机器这个批次中的每一个任务。3.worker采取“抢任务”的方式,这样即使是你在任务处理前1分钟才临时增加10台服务器或者减少5台服务器,系统也自动根据各个服务器的负载情况而自动地调配。因为反应比较慢的烂机器,就没有人家好机器“抢”的多。只不过大型的分布式系统通常用master机的内存状态来协调,而不是像上面那样用数据库记录来协调,只是存储上的区别。4.workder处理完毕之后,根据任务代码编写的业务逻辑,把结果推送到某个地方。例如你的worker可以每当推送结果给某个固定存储地址后,就像client一样去让master机器启动一个reduce任务来合并任务(可以给出积攒了多少内容之后才真正开始合并)。甚至启动一个notifypush任务去向前端设备发送一个“请来读取结果”的通知。分布式处理,是任何一个软件服务公司都最基本的应该掌握的编程知识。不习惯于做这个,跟10几年的走街串巷卖进销存软件的小公司也就差不多了,也就慢慢跟不上最近这几年的时代的步伐了。
解决方案八:
引用5楼ranranshengqi的回复:
关键的问题在于,数据在公网,而工作的几台机器在内网。这样就没有办法通知它们起来工作,除了让它们定时来轮询
如果不在同一个局域网,那么就使用长连接,服务器给客户端推送消息啊。
解决方案九:
你可以看看一个服务器在公网,然后许多客户端在(各自的)局域网内,如何保持双向长连接操作。我在之前贴过一个简单的tcp长连接的底层代码的例子。
解决方案十:
谢谢楼上的高手,受教了!
解决方案十一:
多台机器同时处理数据,防冲突就是加一个状态,谁加了这个状态就由谁处理