何谓:线程 频繁切换???

okmnji79513 2009-12-17 03:15:36
RT
网上看到过,写多线程程序,线程数目较多的话,线程频繁切换,会使程序性能严重下降。那这个 频繁切换 如何理解?

主线程:
type
TMy=class
public
procedure MyTest;
constructor Create(i:integer);
end;

TForm1 = class(TForm)
IdHTTP1: TIdHTTP;
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
function phonenum(i:integer):string;
{ Private declarations }
public
mn:TMy;
procedure MyTest;
procedure My(var msg:TMessage);message WM_My;
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{TMy}
constructor TMy.Create(i:integer);
begin
inherited Create;
end;

procedure TMy.MyTest;
begin
Form1.MyTest;
end;

{TForm1}
procedure TForm1.MyTest;
begin
Memo1.Lines.Add('TForm1 -- MyTest');
end;

procedure TForm1.My(var msg:TMessage);
begin
memo1.Lines.Add('WM_My');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
TAAThread.Create(false);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
mn:=TMy.Create(12);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
mn.MyTest; //----------③
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
MyTest; //----------④
end;


子线程:

Const
WM_My=WM_USER+123;

type
TAAThread = class(TThread)
private
{ Private declarations }
protected
FMessage: String;
procedure LogMessage;
procedure Execute; override;
end;

implementation

uses unit1;

procedure TAAThread.LogMessage;
begin
Form1.Memo1.Lines.Add(FMessage ); //---------------①
// PostMessage(Form1.Handle,WM_My,0,0); //---------------②
end;

procedure TAAThread.Execute;
var i:integer;
begin
FMessage:='Test';
for i:=0 to 100 do
begin
Synchronize(LogMessage);
end;
end;

如上面代码中,Button2 按下,创建了子线程,子线程中频繁的执行了①处代码,这样算 频繁切换 吗?---(1) 那把①处代码换成②处代码,情况又如何?---(2)
请高手们讲解下“频繁切换”吧,最好能 结合个例子,这样好懂点。

另外的问题:我按下 Button4 和 Button5(Button3 已经按过了) 都是打印“TForm1 -- MyTest”,那他们在执行 效率上 有差异不?---(3)
还有我还没按 Button3 ,直接按下 Button4 ,为什么还是能 打印出“TForm1 -- MyTest”?
...全文
493 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
liangpei2008 2009-12-20
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 okmnji79513 的回复:]
对于13楼的 修改,把Synchronize去掉的话,性能上有改善吗?
[/Quote]
去掉是有改善的,但可能会出错,因为VCL大部分组件不是线程安全的。不过可以这样!

type
TAAThread = class(TThread)
private
{ Private declarations }
FLogMessage:TStrings;
protected
FMessage: String;
procedure HookUI;
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy(); override;
end;

implementation

uses unit1;

constructor TAAThread.Create(CreateSuspended: Boolean);;
begin
FLogMessage:=TStringList.Create;
inherited;
end;
destructor TAAThread.Destroy;
begin
FLogMessage.Free;
inherited;
end;

procedure TAAThread.HookUI;
begin
Form1.Memo1.Lines:=FLogMessage; //---------------①
// PostMessage(Form1.Handle,WM_My,0,0); //---------------②
end;

procedure TAAThread.Execute;
var i:integer;
begin
FMessage:='Test';
for i:=0 to 100 do
begin
FLogMessage.add('Log info');
end;
Synchroize(HookUI);
end;

对于Synchroize与PostMessage的区别,我想本质上是一样的!
PostMessage为发送消息给本线程的消息队列,从而进行非阻塞地执行!
而Synchroize则为挂起当前工作线程,把一个无参方法或过程让主线程(VCL线程)执行(阻塞执行)!
对于选择哪种方式,要根据实际情况!
例如说你要发送一个结构体给主线程,且发送完就要释放,这时使用PostMessage就会出问题
okmnji79513 2009-12-19
  • 打赏
  • 举报
回复
对于13楼的 修改,把Synchronize去掉的话,性能上有改善吗?
nanchangfantasy 2009-12-18
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cnzdgs 的回复:]
因为一个处理器同一时刻只能运行一个线程,所以多个线程只能是轮流执行,从执行某一个线程改为执行另一个线程的过程就是线程切换。
频繁切换是指创建了很多个线程,CPU要轮流执行这些线程,因为切换线程需要一定的时间,当线程数量较少时,切换的时间可以忽略不计,而线程数量很多(大约几百个,与物理内存容量有关)时,由于物理内存不足,切换线程需要从虚拟内存中交换数据,所以花费的时间大大增加,导致系统效能降低。
你的程序不存在频繁切换。
[/Quote]
顶二楼的
okmnji79513 2009-12-18
  • 打赏
  • 举报
回复
顶一下,任何其他意见?
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 sanguomi 的回复:]
敲错了
是 完成端口是针对线程切换的系统开销问题
[/Quote]
哦~~~ 完成端口有这样的功效啊, 以前看到相关知识,只是草草看过而已,这下要去翻翻书好好看看了,
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 liangpei2008 的回复:]
cnzdgs老大讲的不错,不过对于以下代码来讲,的确存在性能问题!
Delphi(Pascal) codefor i:=0to100dobegin
Synchronize(LogMessage);//当调用Synchronize时,就会suspend当前线程 ,这样的话,会频繁地在主线程与子线程之间做切换,就起不到线程应有的作用end;
[/Quote]
那不加Synchronize,直接这样:

for i:=0 to 100 do
begin
LogMessage;
end;
效果会怎么样?
hjkto 2009-12-17
  • 打赏
  • 举报
回复
mark
sanguomi 2009-12-17
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 okmnji79513 的回复:]
首先谢谢cnzdgs的讲解,然后对于引用 8 楼 sanguomi 的回复:
所以后来才有了线程池

我不太理解,线程池不是减少线程创建的时间的一种方式吗?对于线程工作中的 频繁切换 也有帮助?请讲解下,谢谢。
[/Quote]

敲错了
是 完成端口是针对线程切换的系统开销问题
liangpei2008 2009-12-17
  • 打赏
  • 举报
回复
cnzdgs老大讲的不错,不过对于以下代码来讲,的确存在性能问题!

for i:=0 to 100 do
begin
Synchronize(LogMessage);//当调用Synchronize时,就会suspend当前线程 ,这样的话,会频繁地在主线程与子线程之间做切换,就起不到线程应有的作用
end;
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
首先谢谢cnzdgs的讲解,然后对于[Quote=引用 8 楼 sanguomi 的回复:]
所以后来才有了线程池
[/Quote]
我不太理解,线程池不是减少线程创建的时间的一种方式吗?对于线程工作中的 频繁切换 也有帮助?请讲解下,谢谢。
sanguomi 2009-12-17
  • 打赏
  • 举报
回复
所以后来才有了线程池
cnzdgs 2009-12-17
  • 打赏
  • 举报
回复
再补充一下,前面所提的“从虚拟内存中交换数据”是针对“性能严重下降”而言的。即使物理内存充足时,切换线程也需要花一些时间(微秒级),如果有几百个线程,轮流执行一次大约要1ms左右的时间用来切换,对于XP系统,时间片是10ms,如果绝大多数线程没有实际工作在做,浪费的CPU资源就比较高了。这种情况如果不能减少线程的数量,则应该把长时间没有实际任务的线程优先级设低一些。
sanguomi 2009-12-17
  • 打赏
  • 举报
回复
要看线程频繁切换,线程要异步执行
WINDOWS95的时间片是20MS,后来版本的不知道
你创建俩个线程异步执行,还是能看到他们之间频繁切换的
Synchronize 你是把你方法放到主线程去执行的
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
[Quote=引用楼主 okmnji79513 的回复:]
如上面代码中,Button2 按下,创建了子线程,子线程中频繁的执行了①处代码,这样算 频繁切换 吗?---(1)    那把①处代码换成②处代码,情况又如何?---(2)
请高手们讲解下“频繁切换”吧,最好能 结合个例子,这样好懂点。
[/Quote]
对于这两个问题,有人不同见解不?


[Quote=引用楼主 okmnji79513 的回复:]
另外的问题:我按下 Button4 和 Button5(Button3 已经按过了) 都是打印“TForm1 -- MyTest”,那他们在执行 效率上 有差异不?---(3)
还有我还没按 Button3 ,直接按下 Button4 ,为什么还是能 打印出“TForm1 -- MyTest”?[/Quote]
对于这两个问题,有人来说下?????
cnzdgs 2009-12-17
  • 打赏
  • 举报
回复
对。只有在创建很多线程时才需要考虑这个问题。
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cnzdgs 的回复:]
因为一个处理器同一时刻只能运行一个线程,所以多个线程只能是轮流执行,从执行某一个线程改为执行另一个线程的过程就是线程切换。
频繁切换是指创建了很多个线程,CPU要轮流执行这些线程,因为切换线程需要一定的时间,当线程数量较少时,切换的时间可以忽略不计,而线程数量很多(大约几百个,与物理内存容量有关)时,由于物理内存不足,切换线程需要从虚拟内存中交换数据,所以花费的时间大大增加,导致系统效能降低。
你的程序不存在频繁切换。
[/Quote]
我还以为 TAAThread 执行到“Form1.Memo1.Lines.Add(FMessage);”时,就要求切到主线程在memo1中打印'Test'(就算TAAThread的时间片还没完),这样 TAAThread 和 主线程 主动的频繁要求切换,这样就是“频繁切换”。
那这样的话“频繁切换”和自己写的代码没关系?只要保证线程不要太多,以致"从虚拟内存中交换数据" 就不会降低性能?
cnzdgs 2009-12-17
  • 打赏
  • 举报
回复
因为一个处理器同一时刻只能运行一个线程,所以多个线程只能是轮流执行,从执行某一个线程改为执行另一个线程的过程就是线程切换。
频繁切换是指创建了很多个线程,CPU要轮流执行这些线程,因为切换线程需要一定的时间,当线程数量较少时,切换的时间可以忽略不计,而线程数量很多(大约几百个,与物理内存容量有关)时,由于物理内存不足,切换线程需要从虚拟内存中交换数据,所以花费的时间大大增加,导致系统效能降低。
你的程序不存在频繁切换。
okmnji79513 2009-12-17
  • 打赏
  • 举报
回复
上面(1)(2)(3)和最后一个问题,请解答下,谢谢。

1,184

社区成员

发帖
与我相关
我的任务
社区描述
Delphi Windows SDK/API
社区管理员
  • Windows SDK/API社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧