请高手们说说Task和Thread的区别

bios8086 2011-08-07 05:29:42
Task应该是4.0中新引进的吧!有没有这方面的范例?
...全文
10507 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
o8jackey8o 2012-08-14
  • 打赏
  • 举报
回复
thread是单核多线程,task是多核多线程,这么简单的问题给你们搞怎么复杂,无语!!!!!
bios8086 2011-08-09
  • 打赏
  • 举报
回复
static void TestThreadCatch()
{
Task mainTask = Task.Factory.StartNew(() =>
{
Task.Factory.StartNew((ii) =>
{
try
{
int k = ((int)ii == 3) ? 0 : (int)ii;
k /=k;
Console.WriteLine("ManagedThreadId:{0}", Thread.CurrentThread.ManagedThreadId);
}
catch (System.ArithmeticException ex)
{
Console.WriteLine(ex.Message);
TestThreadCatch();

}
},0, TaskCreationOptions.AttachedToParent);
});
mainTask.Wait();
Console.WriteLine("Task finished.");
}

谢谢你的帮助,我改写成这个样子应该可以满足我的要求了吧!
bios8086 2011-08-09
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 fangxinggood 的回复:]

[Quote=引用 21 楼 bios8086 的回复:]

[Quote=引用 20 楼 godspeedch 的回复:]

[Quote=引用 19 楼 bios8086 的回复:]

static void TestThreadCatch()
{
Task mainTask = Task.……
[/Quote]
声明自己是robot是不是人家就不会封杀了
机器人 2011-08-09
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 bios8086 的回复:]

[Quote=引用 20 楼 godspeedch 的回复:]

[Quote=引用 19 楼 bios8086 的回复:]

static void TestThreadCatch()
{
Task mainTask = Task.Factory.StartNew(() =>
……
[/Quote]
在 Request Header 的Agent 里声明自己是Robot!
绿色夹克衫 2011-08-09
  • 打赏
  • 举报
回复
感觉lz这个应用用TPL Dataflow(TDF)似乎更合适,不过这方面我了解的不深,从资料来看,主要是针对于TPL对于异步支持不完美,做了一些补充。
bios8086 2011-08-09
  • 打赏
  • 举报
回复
原来微软想的是很周到的,设计的异常机制是很周到的,一个线程有问题,会通知其他所有的线程一起退出,可惜在我这个问题里似乎不需要这样做。

还有第一次在catch 里用递归调用,心里有点异样的激动!有点怕这样做不妥当,但是暂时想不出什么不好的。
bios8086 2011-08-09
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 godspeedch 的回复:]

[Quote=引用 19 楼 bios8086 的回复:]

static void TestThreadCatch()
{
Task mainTask = Task.Factory.StartNew(() =>
{
Task.Fact……
[/Quote]
貌似是有个什么爬虫礼仪的!
如何声明自己是爬虫啊
Howardch 2011-08-09
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 bios8086 的回复:]

static void TestThreadCatch()
{
Task mainTask = Task.Factory.StartNew(() =>
{
Task.Factory.StartNew((ii) =>
……
[/Quote]

对,这样才能并发请求你需要的网页,出错就让他出错吧,任务会自动退出的;而且能得到较好的效率。当然,如果对一个网站并发请求太多的话,有可能被认为是攻击把你给屏蔽了,只是提醒一下,很少有这种策略;据我所知Google map 的static API就有这个策略。
bios8086 2011-08-08
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 gzdiablo 的回复:]

Task是将多个操作封装成一个概念上原子操作。但这个操作由哪个Thread甚至多个Thread来处理处理你并不清楚。总之就是可以被正常完成。
Thread仅仅是一条线程,所有操作都是这个Thread一个人完成的。

Task属于多核开发的封装。跟单线程工作的任务有很大的区别,甚至是本质上的区别。所以可比性不大。当然Task是被封装过的。至于性能如何暂时我还不清楚。

如果谈到多核开发,……
[/Quote]
您的意思是一个Task有可能是由几个线程去协同完成的?
gzdiablo 2011-08-08
  • 打赏
  • 举报
回复
Task是将多个操作封装成一个概念上原子操作。但这个操作由哪个Thread甚至多个Thread来处理处理你并不清楚。总之就是可以被正常完成。
Thread仅仅是一条线程,所有操作都是这个Thread一个人完成的。

Task属于多核开发的封装。跟单线程工作的任务有很大的区别,甚至是本质上的区别。所以可比性不大。当然Task是被封装过的。至于性能如何暂时我还不清楚。

如果谈到多核开发,很多算法上的东西都被改变了。要想深究必须多学习多核的算法。
Howardch 2011-08-08
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 bios8086 的回复:]

我做了如下试验
static int LoadBaseData(int count, CancellationToken token)
{
int result = count;
for (; count > 0; count--)
{
if (token.Is……
[/Quote]

cancellationTokenSource.Cancel实际上是抛出了一个异常,同时IsCancellationRequested一直保持false不会因为一个workitem完成后被重置,因此你后面的任务被取消了。这个代码没有体现并行的优势,请看这段代码。
static void LoadBaseData(IEnumerable<Uri> requestedUris)
{
Task mainTask = Task.Factory.StartNew(() => {
foreach (var uri in requestedUris)
{
Task.Factory.StartNew(tmpUri =>
{
Console.WriteLine("ManagedThreadId:{0}", Thread.CurrentThread.ManagedThreadId);
try
{
GetContentFromUri((Uri)tmpUri);
}
catch { }
}, uri, TaskCreationOptions.AttachedToParent);
}
});

mainTask.Wait();
Console.WriteLine("Task finished.");
}


参数里面的内容是你需要获取的URI集合,当有一个地址不正确,将被捕获,而其他的URI继续进行。这样写只是让你知道可以这样用,而且这样cancellationtoken就没有什么用了,简化代码如下:
Parallel.ForEach(requestedUris, tmpUri => {
Console.WriteLine("ManagedThreadId:{0}", Thread.CurrentThread.ManagedThreadId);
try
{
GetContentFromUri(tmpUri);
}
catch { }
});
绿色夹克衫 2011-08-08
  • 打赏
  • 举报
回复
抓网页的话你看看webClient的异步吧,其中自带了Cancel功能。

[Quote=引用 14 楼 bios8086 的回复:]

To godspeedch:
可能是我没表述清楚,你说我的要求有点奇特我倒是觉得不奇特,比如我分配了20个线程去同时请求20个不同的URL
由于某个原因有那个一两个网站可能是出问题了或者什么的就是连接不上。我当然希望这个线程结束。然后重新去新取一个URL。
我试了线程池和这个Task数组,一取消就是所有的线程一起取消.不知道大家有什么解决的办法
[/Quote]
绿色夹克衫 2011-08-08
  • 打赏
  • 举报
回复
你不用做什么,抛出异常后,微软并行库自己会处理。

[Quote=引用 5 楼 bios8086 的回复:]
引用 3 楼 godspeedch 的回复:
其实task和thread没什么可比性,我们应该比较task和thread pool比较合适。因为他们是处理一类任务的。在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task就是封装后解决这个问题的。当然这个只是小方面。Task还优化了thread pool的调用机制,……
[/Quote]
bios8086 2011-08-08
  • 打赏
  • 举报
回复
我做了如下试验
static int LoadBaseData(int count, CancellationToken token)
{
int result = count;
for (; count > 0; count--)
{
if (token.IsCancellationRequested)
{
break;
}
Console.WriteLine("ManagedThreadId:{0}", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(300);//模拟加载基础数据工作
}

return result;
}
static void TestMyThreadPool()
{

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
cancellationTokenSource.Token.Register(() => Console.WriteLine("操作取消"));
ThreadPool.QueueUserWorkItem(n => { LoadBaseData((Int32)n, cancellationTokenSource.Token); },2);
ThreadPool.QueueUserWorkItem(n => { LoadBaseData((Int32)n, cancellationTokenSource.Token); }, 4);
ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine("ManagedThreadId:{0}", Thread.CurrentThread.ManagedThreadId); });

Thread.Sleep(50000);
cancellationTokenSource.Cancel();
Console.ReadLine();
}
bios8086 2011-08-08
  • 打赏
  • 举报
回复
To godspeedch:
可能是我没表述清楚,你说我的要求有点奇特我倒是觉得不奇特,比如我分配了20个线程去同时请求20个不同的URL
由于某个原因有那个一两个网站可能是出问题了或者什么的就是连接不上。我当然希望这个线程结束。然后重新去新取一个URL。
我试了线程池和这个Task数组,一取消就是所有的线程一起取消.不知道大家有什么解决的办法
Howardch 2011-08-08
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 feixuyue 的回复:]

引用 5 楼 bios8086 的回复:

引用 3 楼 godspeedch 的回复:

其实task和thread没什么可比性,我们应该比较task和thread pool比较合适。因为他们是处理一类任务的。在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task就是封装后解决这个问题的。当然这个只是小方面。T……
[/Quote]

我所谓的没有可比性是因为他们适用的前提不同,你可以想象一个需要中断的任务,你是先考虑thread还是threadpool,另外当你有个任务里面有上百个迭代需要运行,你是考虑用threadpool去帮你管理线程还是自己去创建线程方便?综合来说,task和线程池更相近,所以我们比较他们更有意义。如果说有人喜欢用自己写的线程池,就是另一回事了,呵呵。
Howardch 2011-08-08
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 bios8086 的回复:]

引用 3 楼 godspeedch 的回复:

其实task和thread没什么可比性,我们应该比较task和thread pool比较合适。因为他们是处理一类任务的。在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task就是封装后解决这个问题的。当然这个只是小方面。Task还优化了thread pool的调用机制,……
[/Quote]

这个需求有点奇怪,如果你需要一个线程完成后或者在一个线程抛异常以后再启动另一个线程,就没有必要用TPL了,因为它没用用到多核。MSDN有说明,有两个情况不适合用TPL,一个就是迭代任务很短小,一个就是迭代任务很少;只有在长期的,很多的迭代任务处理中,并行才能体现出好处的。

另外,就你这个问题,你可以用CancellationToken的cancel机制来跳出循环,接着使用task的continue接下一个任务,但是不推荐这样做。
feixuyue 2011-08-07
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 bios8086 的回复:]

引用 3 楼 godspeedch 的回复:

其实task和thread没什么可比性,我们应该比较task和thread pool比较合适。因为他们是处理一类任务的。在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task就是封装后解决这个问题的。当然这个只是小方面。Task还优化了thread pool的调用机制,……
[/Quote]
肯定有,去查下
feixuyue 2011-08-07
  • 打赏
  • 举报
回复
task是根据自己需要调用线程,
thread就是个基本单位
qldsrx 2011-08-07
  • 打赏
  • 举报
回复
一直用BeginInvoke的路过,比较起来还是使用BeginInvoke最好,无需管理线程的终止,设置委托可完成多种多线程后台操作,声明和调用都比Thread方法简单快速。
加载更多回复(6)

110,566

社区成员

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

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

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