搜索
查看: 1602|回复: 17

工作线程与主线程交互的方法

[复制链接]

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
发表于 2017-9-25 18:07:31 | 显示全部楼层 |阅读模式
大家好,多线程学习时候遇到了麻烦,界面线程和工作线程交互有哪位大大可以总结一下?
同样的方式貌似在console和主界面不一致,求助。
以下是我的代码。
希望可以达到类似于这种效果



  1. import win.ui;
  2. import win
  3. /*DSG{{*/
  4. mainForm = win.form(text="aardio form";right=759;bottom=469;cp=1)
  5. mainForm.add()
  6. /*}}*/

  7. i=0;
  8. mainForm.threadCallable();
  9. mainForm.wndproc = {
  10.         [0x202/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){
  11.                 var x,y = win.getMessagePos(lParam);                               

  12.                 mainForm.add(
  13.                         ["btn"+i]={
  14.                                 cls="static";left=x;top=y;z=1;text="0.00";bottom=y+20;right=x+100;id=i;autoResize=false;
  15.                         };
  16.                 );
  17.        
  18.                
  19.                 thread.invoke(                     
  20.                         function(winform){       
  21.                             //import win;               
  22.                             import console;
  23.                                 for(j=1;4;1){       
  24.                                                 //为何下面这句 界面线程没法执行
  25.                                                
  26.                                                 // winform.add(["btn"+i]={
  27.                                                 //        cls="static";left=x;top=y;z=1;text=j;bottom=y+20;right=x+100;id=i;autoResize=false;
  28.                                                 // });
  29.                                                
  30.                                                 //console 可以正常执行
  31.                                                 console.log(j)
  32.                                                 sleep(1000);                                       
  33.                                         }               
  34.                                 },mainForm
  35.                 )
  36.                
  37.                 i=i+1;
  38.         }
  39.        
  40. }


  41. mainForm.enableDpiScaling();
  42. mainForm.show();

  43. return win.loopMessage();
复制代码
回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-26 15:53:19 | 显示全部楼层
最终完成了,多谢,借鉴了 thread.command 完成了

代码如下:
  1. import win.ui;
  2. import win
  3. /*DSG{{*/
  4. mainForm = win.form(text="aardio form";right=759;bottom=469;cp=1)
  5. mainForm.add()
  6. /*}}*/

  7. var i=1;   //aardio 控件ID从1开始,不是0,切记切记
  8. mainForm.wndproc = {

  9.         [0x202/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){
  10.                 var x,y = win.getMessagePos(lParam);
  11.                 mainForm.add(
  12.                         [i]={
  13.                                 cls="static";left=x;top=y;z=1;text="0";bottom=y+20;right=x+50;id=i/*控件ID*/;autoResize=true;
  14.                         };
  15.                 );
  16.                 //每次单击创建一个线程                       
  17.                 thread.invoke(
  18.                             function(id){
  19.                                 import thread.command;  
  20.                                 for(j=1;1000;1){  
  21.                                     // 方法1                                     
  22.                                         //thread.command.post("show",id,j);
  23.                                         //  方法 2  对比 thread
  24.                                         thread.command.show(id,j)
  25.                                         sleep(100)
  26.                                 }                   
  27.                                
  28.                             },i
  29.                         );
  30.                 i=i+1;
  31.         }
  32.        
  33. }

  34. import console

  35. var ls=thread.command();
  36. ls.show = function(id,j){       
  37.         var ctrl=mainForm.getCtrlById(id);
  38.                 ctrl.text=j;       
  39. };

  40. mainForm.enableDpiScaling();
  41. mainForm.show();

  42. return win.loopMessage();
复制代码
回复

使用道具 举报

0

主题

23

帖子

116

积分

一级会员

Rank: 2

积分
116
发表于 2017-9-25 18:41:19 | 显示全部楼层
界面线程与工作线程交互的方法参考aardio自带的范例、入门教程,
打开aardio在开始页、范例就能看到。

即然你在询问“交互”的方法,那么你应该已经了解aardio线程的变量是隔离的。
你的console访问的是本线程的变量所以正常,而你出问题的代码直接使用了外部线程的变量。
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-26 16:52:38 | 显示全部楼层
id从哪开始不是个问题吧,从几千开始都常见,
而且没必要弄的这么复杂吧,只要简单的拿个句柄任何事都可以做了。

  1. import win.ui;
  2. /*DSG{{*/
  3. mainForm = win.form(text="aardio form";right=759;bottom=469)
  4. /*}}*/

  5. var i = 0;
  6. mainForm.wndproc = {
  7.     [0x202/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){  
  8.         
  9.                 var x,y = win.getMessagePos(lParam); i++;
  10.                 mainForm.add(  ["btn"+i]={ cls="static";left=x;top=y;z=i;text="0";bottom=y+20;right=x+50;};   );
  11.                
  12.                 thread.invoke(
  13.                         function(hwnd){
  14.                                 import win;
  15.                                 for(j=1;1000){win.setText(hwnd,tostring(j)); sleep(100)   }   
  16.                         },mainForm["btn"+i].hwnd
  17.                 );
  18.     }
  19. }

  20. mainForm.show();
  21. win.loopMessage();
复制代码
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-26 17:09:18 | 显示全部楼层
跨线程直接调用控件对象的版本:

import win.ui;
/*DSG{{*/
mainForm = win.form(text=
"aardio form";right=759;bottom=469)
/*}}*/

var i = 0;
mainForm.wndproc = {
    [0x202
/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){  
        
        
var x,y = win.getMessagePos(lParam); i++;
        mainForm.add(  [
"btn"+i]={ cls="static";left=x;top=y;z=i;text="0";bottom=y+20;right=x+50;}; );
        mainForm[
"btn"+i].threadCallable();
        
        thread.invoke(
            
function(ctrl){
               
for(j=1;1000){
               
                   ctrl.text = j;
                    
sleep(100);
                }   
            },mainForm[
"btn"+i]
        );
    }
}

mainForm.show();
win.loopMessage();
昨天在测试这段代码时发现threadCallable()一个藏的较深的BUG会导致这段代码异常(新版aardio已修正)。

回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-26 17:10:41 | 显示全部楼层

使用 thread.command 实现的版本

import win.ui;
/*DSG{{*/
mainForm = win.form(text=
"aardio form";right=759;bottom=469)
/*}}*/

var i = 0;
mainForm.wndproc = {
    [0x202
/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){  
        
        
var x,y = win.getMessagePos(lParam); i++;
        mainForm.add(  [
"btn"+i]={ cls="static";left=x;top=y;z=i;text="0";bottom=y+20;right=x+50;}; );
        
        thread.invoke(
            
function(id){
               
import thread.command;
               
for(j=1;1000){
                    thread.command.post(
"updateStatic",id,j);
                    
sleep(100);
                }   
            },i
/*传给线程参数*/
        );
    }
}

import thread.command;
thread.command.instance().updateStatic =
function(id,str){
    mainForm[
"btn"+id].text = str;
}


mainForm.show();
win.loopMessage();

回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-26 17:17:30 | 显示全部楼层

用定时器实现的版本

线程与界面的接口应当设计一个简洁的交互界面,界面自己的事可以界面线程里自己解决,例如用定时器:
import win.ui;
/*DSG{{*/
mainForm = win.form(text=
"aardio form";right=759;bottom=469)
/*}}*/

var i = 0;
mainForm.wndproc = {
    [0x202
/*_WM_LBUTTONUP*/] = function(hwnd,message,wParam,lParam){  
        
var x,y = win.getMessagePos(lParam); i++;
        mainForm.add(  [
"btn"+i]={ cls="static";left=x;top=y;z=i;text="0";bottom=y+20;right=x+50;}; );

        
var ctrl = mainForm["btn"+i];
        mainForm.addtimer( 100,
function() ctrl.text = ctrl.text + 1;)
    }
}

mainForm.show();
win.loopMessage();


回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-27 21:45:18 | 显示全部楼层
嗯,谢谢.

三种方法有一些差异;

我试了一下三种方法,在我的WIN10上面可以参考下(DELL INSPERION 14 /CPU I3 4500U /1.7G RAM 4G)

跨线程直接调用控件对象的版本:
最大创建110多个线程 ,后面就卡住了,线程完毕后又可以重新创建;功能正常;
添加transparent=true后:最大只有32个;

用定时器实现的版本:
     创建超过270个定时器(也许更多,没有尝试);功能正常;
    添加transparent=true后:最大超过140个,110个以后定时器明显变慢差不多1s变形一次
使用 thread.command 实现的版本:
最大创建110个线程 ,后面就卡住了,线程完毕后又可以重新创建;功能正常;
添加transparent=true后:最大只有58个;
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-27 22:04:24 | 显示全部楼层
waleson 发表于 2017-9-27 21:45
嗯,谢谢.

三种方法有一些差异;

你这个属于误解,

一般不会用多线程仅仅是为了操作界面对象,
因为界面对象上的所有操作实际都只是运行在一个单线程里,也就是win.loopMessage();这个消息循环里执行所有的操作。你用大量的多线程操作界面,界面的消息循环堵塞了,当然就要等待。

你认为定时器正常,那时因为定时器会丢弃消息,之所以你没有发现,是因为你创建了太多的快速刷新的控件。

一个控件每秒刷新几百次,人的眼睛就看不过来了,
更何况是几百个控件在这样的刷新?! 做这种测试的实际意义是什么呢?!
我觉得最没有意义的就是测试这种空循环的任务。

很多人以为跑空循环汇编语言速度快、C语言速度快,
但实际上我们的编程语言不仅仅是用来跑空循环的,这就好像让先进的大型战车,跟一个幼儿园的小朋友比赛跳一级台阶谁利索,当然是幼儿园的小朋友完胜。

回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-27 22:05:29 | 显示全部楼层
直接句柄法:

创建最大250个线程,正常;后面就没法显示了;线程完毕后又可以重新创建;功能正常
添加transparent=true后:最大105个,且每次显示不正常——重影;

综上看来: timer方法是个不错的方法。
回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-27 22:10:20 | 显示全部楼层
嗯,是的。

本质上是没有什么意义,一般也不会使用这么多消息;


最大线程数量有没有什么限制?
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-27 22:32:04 | 显示全部楼层
你这里用多线程,线程什么都不干,全都阻塞在界面里,当然不如在单线程里用定时器。

这就好像你修了250条大马路在桥边,再源源不断的送人过来过河。
结果你发现250条大路太不争气了,过河的人还不如原来只有一条马路的。
这个逻辑是哪跟哪呢?!

你认为定时器快,那是因为定时器忙不过来会把消息丢掉。
这就好像你一拍脑袋,把桥栏杆拆了,结果挤不过来的人全掉河里淹死了。
你高兴的说:大桥正常了,再也不会挤死人了。
不挤死人但是会淹死人啊?!
回复

使用道具 举报

3

主题

51

帖子

308

积分

二级会员

Rank: 3Rank: 3

积分
308
发表于 2017-9-27 22:46:52 | 显示全部楼层
感觉楼主纠结了,花费大量的时间做了无意义的事,还是多做点实在的吧!

如果时间多,多写写教程帮助新人
回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-27 22:47:57 | 显示全部楼层
Jacen.He 发表于 2017-9-27 22:32
你这里用多线程,线程什么都不干,全都阻塞在界面里,当然不如在单线程里用定时器。

这就好像你修了250 ...

这个比喻很恰当!

也就是说那些测试看起来卡,实际上只是由于主界面线程消息队列阻塞,导致_wm_mouseup消息没法继续被执行/消费,导致的形成了4种方法的表象的极限现象。真正的线程还是可以使用其他工作线程创建的?
回复

使用道具 举报

4

主题

18

帖子

99

积分

一级会员

Rank: 2

积分
99
 楼主| 发表于 2017-9-27 22:53:05 | 显示全部楼层
幻月 发表于 2017-9-27 22:46
感觉楼主纠结了,花费大量的时间做了无意义的事,还是多做点实在的吧!

如果时间多,多写写教程帮助新人

晕。。。

我也是新人啊,接触还没有超过1个月。。。

就想通过类似的项目来学习,将一些不明白的地方搞清楚,对其他的新人也是一个借鉴

如果嫌麻烦打扰了,诚恳说声 对不起!
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-27 22:56:07 | 显示全部楼层
你的电脑能创建多少线程,这要看你的系统资源,普通的电脑创建1000个线程以上应当可以。
但通常不太可能有软件需要创建如此多的线程,一般的软件运行时的线程数基本不会超过50个,大多数应该不超过10个线程。
所以基本上软件开发不太需要考虑这个问题。

我以前看过一个人写程序,他后台用的多线程,处理数据非常快,每次都刷新界面,结果他生气的说用了多线程并没有更快,反而卡的不行。然后我跟他说,你的软件界面每秒重绘几千上万次,人类的眼睛能看过来吗?!然后他改进了程序,减少了不必要的重绘界面的次数,软件瞬间就变的轻快利索了。

所以软件的性能瓶颈通常不在界面上
回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-27 22:58:32 | 显示全部楼层
waleson 发表于 2017-9-27 22:47
这个比喻很恰当!

也就是说那些测试看起来卡,实际上只是由于主界面线程消息队列阻塞,导致_wm_mouseu ...


我没有去点击那么多次做测试,但看代码和你的描述应该是界面的消息循环处理不过来。

另外任何线程都可以继续创建其他线程。但一般可能会搞一个线程队列、或线程管理器以避免创建太多线程

回复

使用道具 举报

186

主题

2536

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
13930
发表于 2017-9-27 23:22:11 | 显示全部楼层
waleson 发表于 2017-9-27 22:53
晕。。。

我也是新人啊,接触还没有超过1个月。。。

我觉得没有关系,喜欢钻研不管对和错都是好习惯。
幻月的话也有一定的道理,做技术有所放弃,有所选择,可以把我们有限的时间用到刀刃上。
但我们很多时候,需要走弯路才能找到更好的路子。所以只要肯钻研技术,不管是纠结的对,还是纠结的错,都是好的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|站长邮箱|aardio.com|aardio官方社区 ( 皖ICP备09012014号 )

GMT+8, 2018-8-15 10:45 , Processed in 0.078126 second(s), 24 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表