Foxtable(狐表)用户栏目专家坐堂 → [求助]多线程的问题


  共有5561人关注过本帖树形打印复制链接

主题:[求助]多线程的问题

帅哥哟,离线,有人找我吗?
chnfo
  11楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/21 18:52:00 [显示全部帖子]

怕什么果然就是什么。
实际的系统是一个比较大的系统,远不是示例上的三个表。而且表列也远不上示例上的那么简单几列。
最开始是用的ACCESS数据库。
然后做法也直接采用SQL执行的(跟上面蓝版主说的方法大同小异),界面也不是单纯的一个表,还有树形结构、还有递归计算等。
但执行之后发现耗时需要约14秒,这个速度显然是不能让人满意的。
然后改换了SQL2005,效率有所提升,但仍然需要10秒钟。

经过实际测试,发现一个问题。比如界面上要计算的是5列(上传的示例是2列,它们的计算来源于5个相互独立的数据库表),如果逐一执行的话,每个都需要1.5秒钟,那就得要7.5秒。
所以,我在想,如果开启5个线程同时来计算这5列的值,会不会减少6秒的计算时间呢?

而我又不能把整个系统搬到示例中来,所以举了一个简单的例子传上来,希望获取一个方法,用这个多线程的方法来检验系统的执行时间是否会减少

以上传的例子来说的话,导致执行时间长的原因可能是两个
1、商品目录行数太多(实际系统有些业务达到4-10万行的数据量)
2、要计算的列多了一点(示例是2列,但目前实际系统计算的值,其中一项业务是8列)
[此贴子已经被作者于2019/2/21 19:00:08编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  12楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/21 22:35:00 [显示全部帖子]

纵向可以按属性进行分,也就是上面说的按列,因为每列的数据来自一个表,那么可以5列开5个线程,可以先把这些表指定时间段内的所有商品的数据都汇总出来保存到临时表中,最后像21楼那样,一条SQL关联把这些数据都提取出来即可

----保存到临时表。但前面提到多线程对操作表的支持性不太好,那该如何处理呢?
如果设计一个临时表,把商品目录filler进来,这个不是问题。
但怎么保存分别计算出来的这5列数据?

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  13楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/21 22:44:00 [显示全部帖子]

执行过程中建一个临时表可不可以?
因为如果在数据库中建表,A店的人在操作,B店的人也在操作,这个临时表可能会有问题

啊哦,不行,SQL不支持临时表的操作
[此贴子已经被作者于2019/2/21 22:47:48编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  14楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/21 22:59:00 [显示全部帖子]

这样做可能还是会有问题。
因为tbRK的操作可能不是一个人。如果某一个店有多个人在操作,张三正在查看3月份的数据,李四想查看4月份的数据,而王五想填写5月份的数据。
如果临时表中的字段包括店名、商品ID、已调整数量、已入库数量,那么就不能同时满足三个人看数据的要求。
除非临时表中的字段再增加一列月份。

但这样设计,就有个弊端,并非每种商品每个月都有调整、或每个月都有入库,这个数据复制的行数就很多,而且似乎并无太大意义。

[此贴子已经被作者于2019/2/21 23:01:09编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  15楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/21 23:27:00 [显示全部帖子]

不是这个意思,我是说同一家店,张三在看3月的数据,李四看4月的,王五在看5月的,三个人同时看,不就麻烦了?因为每个月的已入库数量是不同的嘛。截止3月的已入库明细和数量、截止4月的、截止5月的,都不尽相同啊

因为要查看3月的数据,要显示截止3月的调整总量、已入库量、本月入库量,而不是仅仅看3月入库量这一列。

所以,最后还是回到你说的那条老路子上,每个月把所有目录的最新调整后、已入库量、本月入库量存一遍。
[此贴子已经被作者于2019/2/21 23:37:46编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  16楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/23 15:17:00 [显示全部帖子]

蓝版主,把所有的数据按调整、入库每个月都存一个最新值然后按需要调用,有一些其它的问题暂时不好解决(数据库的调整影响比较大),暂时不想动它了,还是用后台SQL查询来解决,多列多线程查找赋值,用的时间可能比直接取用时间长一点,再想其它的办法吧。现在多线程专业问题请教。

比如说在全局代码中定义一个线程“XC001”
Public Sub XC001(ByVal cr As Object,ByVal s As Object)
    functions.Execute("JS01", cr,s)
End Sub


然后在自定义函数中定义一个函数“JS01”
dim r as row = args(0)
dim s as integer = args(1)
dim dt as datatable
c m d . C o n n e c t i o n N a m e   =   " P M "
cmd.CommandText = "外部连接数据库SQL"
dt = cmd.ExecuteReader()
Return dt   ‘函数运行的结果返回dt

那么开启多线程该怎么整?象下面这样
vars("数量1计算完成")  = false
Dim t1 As Threading.Thread =  New Threading.Thread(AddressOf XC01)
t1.Start(r,1)
vars("数量1计算完成")  = true

'同理计算数量2
vars("数量2计算完成")  = false
Dim t2 As Threading.Thread =  New Threading.Thread(AddressOf XC02)
t2.Start(r,2)
vars("数量2计算完成")  = true

if vars("数量1") = true andalso vars("数量2") = true  then 
'执行代码,因为这段代码要利用数量1和数量2的计算结果
end if 

但是,启动线程之后希望得到函数的计算结果(就是return dt的那个dt),应当怎么做呢
[此贴子已经被作者于2019/2/23 15:42:36编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  17楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/2/24 21:45:00 [显示全部帖子]

蓝版主,实际测试的情况是,开启两个线程分别计算调整值和已入库值,在商品目录是4万行时,用时几乎就是秒杀。
反而是把这4万行的数据赋值到界面上的速度慢。实际测试赋三列的值用时近7秒钟。
我看到帮助里的“查询与赋值并存”说1万行赋值约0.8秒,看来也就是这个效率了。

看来还得想其它的招来解决计算结果赋值的问题。
而且,赋值完成以后,还有递归计算的工作要处理。性能优化,任重道远啊。

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  18楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/3/12 22:35:00 [显示全部帖子]

1、常规做法,我的示例中已经做了。也能实现功能。但是在数据量大的情况下,速度慢,比如要做5列的数据赋值,光执行SQL都要10秒左右,这个我自己都受不了,更别说用户了。
2、蓝版主,不能拿这个示例来就事论事。因为现在的系统不是单一功能,也没法把整个系统都传到这里,只是借这个示例来说明一下,如何来提高效率(包括SQL计算、赋值,用多线程处理或者存储过程处理是否能优化,或者用临时表、临时列、数据冗余等等)

主要意图如下:
1、点TbAlter的行,打开模式窗口AlterD,在窗口中把在本次调整日期之前调整过的量显示出来,然后填写本次的调整量
2、点TbRK的行,打开模式窗口RKD,在窗口中把本次入库日期之前已经调整过的量、之前已经入库过的量显示出来,然后填写本次入库的数量、单价、其它费用

在数据量大的时候,第二步时,如果逐一执行SQL赋值,用时会比较长;如果要计算4列或5列的值就会更长(这里可能开启多线程会减少一部分时间)

 下载信息  [文件大小:   下载次数: ]
图片点击可在新窗口打开查看点击浏览该文件:多线程处理大量数据.zip



[此贴子已经被作者于2019/3/12 22:38:09编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  19楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/3/13 20:38:00 [显示全部帖子]

异步函数不能操作界面表数据,只能操作后台数据,所以,是否用异步函数对上面的示例来说似乎并无太大意义,因为可以开启多线程直接执行SQL并赋值给全局代码中定义的表(例如示例的DTRKD)。

然后接下来就是将DTRKD中的值赋值给界面表了。帮助里也说了,多线程不能操作界面表,所以赋值只以依次执行了,这个时间估计很难优化。除非利用其它的方法,不用字典。

至于实例无法测试耗时,如果我把物资目录搞到几万行,然后做个十期八期调整记录、再做个几十期入库明细,那数据就太大,论坛都不让上传了。
所以,实际数据可以用随机函数,增加多期数据来测试。
[此贴子已经被作者于2019/3/13 20:38:09编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
chnfo
  20楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:九尾狐 帖子:2199 积分:18081 威望:0 精华:0 注册:2011/11/26 20:21:00
  发帖心情 Post By:2019/3/13 21:28:00 [显示全部帖子]

不清楚你的逻辑,你可以处理数据都在后台数据表啊,最后一次性把数据加载显示出来即可
----这个就象前面的示例。
比如说我想在办理入库的时候,已知它们的初始计划数量A,但同时想知道各种物资截止目前为止的调整数量B(它来源于tbAlterD),同时想知道它截止上次入库为止已经入库的数量C(它来源于TbRKD表),这样才能办理入库(因为要求入库的数量不能超计划,也就是本次入库的数量必须不能大于A+B-C)

象你所说的在后台数据表,是说全局代码表,还是后台的数据库实体表呢?
如果是全局代码表还好一点,要是数据库实体表要实时保存B和C,涉及到多人同时操作时,可能会有不可预知的麻烦,比如说数据同步计算错误,甚至会不会导致数据库死锁。

基于这种考虑,我才想着在客户端动态计算B和C值,虽然也有可能导致多人同时操作时会有违背这个业务规则的数据发生,但可以有数据统计功能向用户提示这种非法数据。这样也免去了频繁更新后台数据的情况。冗余有一定的好处,但这种情况下冗余的设计可能并不是个好方案

至于赋值的数据冲突,应当不会有太大的问题。因为B列和C列的数据来源于不同的表,而且全局代码表设了两个,分别来做B和C所需的值的计算,在统计和赋值上应当不会有冲突。


其实,我也想过用一个全局代码表X,让它执行SQL,合并B和C的统计,这个SQL比较复杂了,什么left join之类的嵌套一堆看得我眼晕,然后界面表的源就直接设为X,然后加载,但实际效率不理想,因为数据量太大了,本身SQL执行的速度就不快。

后来考虑了一种方案,就是把物资按它们所属的分类整成树,点击树节点的时候,就只加载这个节点(以及它的所有子节点)的物资,这样,计算量会明显小很多。比如说物资分为10类,就算每一类有4000种,也比一次性计算和加载4万行要快得多。

本来按我的想法,物资明细搞个两三千行就已经很大了,没想到用户搞出来的明细数量将近10万行(我一看就几乎晕倒),想让用户搞简化一点,用户不接受,没办法,只能照办
[此贴子已经被作者于2019/3/13 21:43:14编辑过]

 回到顶部
总数 30 上一页 1 2 3 下一页