C# TPL并行只执行一部分就退出,求解?

qingfy2007 2013-08-17 11:46:47
背景介绍:

开发环境 :VS2010简体中文旗舰版
.net 版本:.net4.0
CPU :双核四线程【Intel】
错误现象 :使用 TPL 编写多核并行代码,发现只并行了其中的一部分(不能并行到底),之后就由一条线程执行到结束。编译时,代码没有问题,运行时,有时候出现运行到一定程度,程序就卡住,不再执行下去,就像死机一样。下面就贴出代码。
...全文
179 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
threenewbee 2013-08-18
  • 打赏
  • 举报
回复
当然了,在非UI线程操作界面需要使用Control.Invoke让界面去刷新。
qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
以下将展示窗体调用部的代码,窗体中新建了一个按钮,使用按钮的 Click 事件执行并行程序,代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using SyncThread;

namespace TestThread
{
public partial class Form1 : Form
{
private SyncThread.DoWork dw; // 声明类;
private ShowInfo sf; // 声明委托;
//
// 委托;
//
private delegate void ShowInfo( System.Windows.Forms.RichTextBox txt );
private void showInfo( System.Windows.Forms.RichTextBox txt )
{
this.dw.txt = txt;
}

private void controlShow()
{
if( this.InvokeRequired ) // 返回值为 true,表示来自 UI 线程;
//if ( true ) // 返回值为 true,表示来自 UI 线程;
{
Object[] value = { this.txtShow };
this.Invoke(this.sf, value);
}

this.dw.handle();
//this.dw.doParelWork();
}

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
this.dw = new SyncThread.DoWork( this.txtShow ); // 实例化类;
this.sf = new ShowInfo(this.showInfo); // 实例化;
}

private void cmdStart_Click( object sender, EventArgs e )
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; // 这句话也可以加在这里,这么搞;
controlShow();
}
}
}

执行结果描述如下:
1、执行时,没有一次并行到底,总是:并行了其中一部分(不能并行到底),之后由一条线程执行到结束;
2、有时候程序中途卡住,就像死机了一样,不响应系统的任何操作,但是系统的其他程序可以正常运行;
3、有时候报告错误。




qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
上面的代码说明了 C# 的并行是没有问题的,下面我稍微修改了一下实现,即:将打印的位置由控制台转到 RichTextBox 中,现封装一个 C# DLL以具体实现并行代码,之后,创建一个应用窗体程序,由该程序去调用。 C# DLL: using System; using System.Collections.Generic; using System.Linq; using System.Text; //using System.Core; using System.Data; //using System.Data.DataSetExtensions; using System.Xml; using System.Xml.Linq; using System.Threading; using System.Windows.Forms; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace SyncThread { public class SyncMethod { public System.Windows.Forms.RichTextBox txt; // 指定要输出文本的文本框; static System.Threading.Semaphore sep = new System.Threading.Semaphore(10, 100); public SyncMethod( System.Windows.Forms.RichTextBox txt ) { this.txt = txt; } public void printMessage( String str,int index ) { System.DateTime dt = System.DateTime.Now; if( null == this.txt ) { MessageBox.Show( " txt 值为空!" ); return; } for( int i = 0; i < 5000; i++ ) { this.txt.AppendText( "当前时间 " + String.Format("{0:yyyy-MM-dd HH::mm::ss}", dt) + " " + str + " = " + i + " " + index + "\n" ); // 注意时间的格式化; sep.Release(); // 释放自增减锁; } } }; public class DoWork { private SyncMethod st1; private SyncMethod st2; private SyncMethod st3; private SyncMethod st4; public System.Windows.Forms.RichTextBox txt; public DoWork( System.Windows.Forms.RichTextBox txt ) { this.txt = txt; this.st1 = new SyncMethod( this.txt ); this.st2 = new SyncMethod( this.txt ); this.st3 = new SyncMethod( this.txt ); this.st4 = new SyncMethod( this.txt ); } public void handle() { System.Threading.ThreadStart del = delegate() { try { System.Threading.Tasks.Parallel.Invoke( () => this.st1.printMessage( "aaaa",1111 ), () => this.st2.printMessage( "bbbb",2222 ), () => this.st3.printMessage( "cccc",3333 ), () => this.st4.printMessage( "dddd",4444 ) ); } catch (System.AggregateException) { } catch (System.Exception) { // System.Windows.Forms.MessageBox.Show("出现其他错误," + "出错原因:" + e.Message); } }; System.Threading.Thread th = new System.Threading.Thread( del ); th.IsBackground = true; th.Name = "dowork"; th.Start(); } public void doParelWork() { try { System.Threading.Tasks.Task t1 = new System.Threading.Tasks.Task(() => this.st1.printMessage("aaaa", 1111)); System.Threading.Tasks.Task t2 = new System.Threading.Tasks.Task(() => this.st2.printMessage("bbbb", 2222)); System.Threading.Tasks.Task t3 = new System.Threading.Tasks.Task(() => this.st3.printMessage("cccc", 3333)); System.Threading.Tasks.Task t4 = new System.Threading.Tasks.Task(() => this.st4.printMessage("dddd", 4444)); t1.Start(); t2.Start(); t3.Start(); t4.Start(); System.Threading.Tasks.Task.WaitAll( t1, t2, t3, t4 ); } catch (System.AggregateException ex) { } catch (System.Exception e) { } } } }
  • 打赏
  • 举报
回复
另外,你在 catch (System.AggregateException ex)那个地方设置断点你就知道什么错误了,是Semaphore的问题。
  • 打赏
  • 举报
回复
看得出你不会使用System.Threading.Semaphore,最简单的方法就是把它去掉。
  • 打赏
  • 举报
回复
把你的 this.Invoke 改为 this.BeginInvoke。 我印象中,我好像从来没有使用过 Invoke,都是 BeginIncoke。我从来都非常注意不要稀里糊涂地写出阻塞式的程序。
qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
【 SQL_Beginner Debugging之傲气魔君】: 你好,那两行我已经注释了的(见 11 楼 本人回复),你说的: if( this.InvokeRequired ) // 返回值为 true,表示来自 UI 线程; //if ( true ) // 返回值为 true,表示来自 UI 线程; { Object[] value = { this.txtShow }; this.Invoke(this.sf, value); } 根本不起作用,是真的,感谢赐教。 使用:CheckForIllegalCrossThreadCalls 是因为我是用线程启动并行程序的,这种方式可行,因为控制台程序也是用这种方式启动的。 我可以把代码传给你。你帮我看看,可否? 我QQ:756385819
  • 打赏
  • 举报
回复
哎,把 static System.Threading.Semaphore sep = new System.Threading.Semaphore(1, 4);
跟sep.Release(); 那两行注释掉就那么难吗?
实在搞不懂你这里用Semaphore来做什么,如果你真的控制并发度应该由Parallel.Invoke ParallelOptions来控制啊。
还有,你的程序问题很多,很多代码写的很随意的, 下面的代码要它干嘛的?根本起不到作用。
if( this.InvokeRequired ) // 返回值为 true,表示来自 UI 线程;
//if ( true ) // 返回值为 true,表示来自 UI 线程;
{
Object[] value = { this.txtShow };
this.Invoke(this.sf, value);
}

另外,我就好奇为什么你能在main thread之外更新线程了,原来你用了CheckForIllegalCrossThreadCalls,这????
qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
我尝试着放弃了 Semaphore ,即把:

static System.Threading.Semaphore sep = new System.Threading.Semaphore(1, 4);
sep.WaitOne();
sep.Release();

注释掉,结果发现,执行到了几百次就卡住了,程序无法执行下去,就像这个程序死了似的,贴图佐证:

  • 打赏
  • 举报
回复
你就把Semaphore去掉好拉。
你把System.Threading.Semaphore(10, 100);改为System.Threading.Semaphore(1, 4);还是勿用Semaphore。
我就不相信你那个sep.Release(); 4次循环后不会报错。但或许你看不到,你因为你吞掉了exception。
qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
刚才点错了,现在贴并行的图片:


再次提问:

1、为什么 CPU 的使用率只有 40% ,而控制台的使用了可以到达 95%?

2、如何提高 CPU 的使用率?

求指点,TKS
qingfy2007 2013-08-18
  • 打赏
  • 举报
回复
感谢以上各位的热情回复,我突然发现我写错了一句代码:
static System.Threading.Semaphore sep = new System.Threading.Semaphore(10, 100);

因为我只启动四条线程,所以这句代码应该是:
static System.Threading.Semaphore sep = new System.Threading.Semaphore(1, 4);

现在可以并行到底了,但是 CPU de 的使用率 只有 40% ,并不高,以下贴图佐证:


并行贴图展示:


再问:
qingfy2007 2013-08-17
  • 打赏
  • 举报
回复
首先贴出控制台执行程序,验证该代码是正确的。代码具体如下:
using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;

using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Test
{
class A
{
public String strName;

public A( String str )
{
this.strName = str;
}

public void printMessage()
{
System.DateTime dt = System.DateTime.Now;

for( int i = 0; i < 50000; i++ )
{
Console.WriteLine( "当前时间 " + String.Format( "{0:yyyy-MM-dd HH::mm::ss::ffff}",dt ) + " " +
" i = " + i + " " + this.strName ); // 注意时间的格式化;
}
}
}

class Program
{
static void Main( string[] args )
{
A a1 = new A( "11111" );
A a2 = new A( "22222" );
A a3 = new A( "33333" );
A a4 = new A( "44444" );


System.Threading.ThreadStart del = delegate()
{
try
{
System.Threading.Tasks.Parallel.Invoke(
() => a1.printMessage(),
() => a2.printMessage(),
() => a3.printMessage(),
() => a4.printMessage()
);
}
catch( AggregateException ex )
{
System.Windows.Forms.MessageBox.Show( "出错了!" + "出错原因:" + ex.Message );
}
};

System.Threading.Thread th = new System.Threading.Thread( del );
th.IsBackground = true;
th.Start();

Console.WriteLine( "单击任意按键可结束测试!" );
Console.ReadKey();
}
}
}

贴出图片,可以看出并行代码执行OK,且能执行到底。

110,566

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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