新人之解决多线程修改DataTable的方法

hb1122 2010-04-16 01:03:31
最近用到了多线程,能让多核CPU全部开启,效率变得很高,可惜在使用的时候,由于要对DataTable进行操作,调试时报错。
查阅了下资料,也询问了些高手,发现是DataTable不是线程安全,无法在多线程中同时操作。
由于刚接触.net不久,不了解lock等,结合CSMA/CD的冲突处理方式,用笨方法做了一个多线程按序操作DataTable的方法



在实例类的时候,取得现在线程的当前托管线程的唯一标识符。

 Public Class getproduct
'取产品

Private tid As Integer
......


Public Sub New(ByVal _Dc_ID As String, ByVal _site As String)
tid = Threading.Thread.CurrentThread.ManagedThreadId
......
End Sub
End Class


当进行DataTable操作时
Private Sub prodsave(ByVal _name As String, ByVal _link As String)
Do
If tableid = Nothing Then
tableid = tid
Threading.Thread.Sleep(10)
If tableid = tid Then

......
tableid = Nothing
Exit Do
End If
Else
Threading.Thread.Sleep(getrand)
End If

Loop
End Sub


模块

Module wc
Public tableid As Integer = Nothing
End Module


这样在进行DataTable操作时,就能避免多线程同时操作了!

:)


开8线程,CPU使用率能达到60%以上,数据速度很快。

笨方法,高手有好方法请不吝赐教!
...全文
744 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
heiwer 2010-04-19
  • 打赏
  • 举报
回复
synclock 上锁
billow_chentao 2010-04-18
  • 打赏
  • 举报
回复
回复内容
xingyuebuyu 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hb1122 的回复:]
引用 5 楼 xingyuebuyu 的回复:
VB.NET code
Private Sub prodsave(ByVal _name As String, ByVal _link As String)
Do
If tableid = Nothing Then
tableid = tid
Threading.Thread……


呃,多个线程同一时间赋值,最终10ms过后,只会……
[/Quote]

写的时候只有一个能写,其它的都需要等待,读的时候其实不需要锁定.
系统提供了 System.Threading.ReaderWriterLock 类,不过据说性能不够好
hb1122 2010-04-16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 xingyuebuyu 的回复:]
VB.NET code
Private Sub prodsave(ByVal _name As String, ByVal _link As String)
Do
If tableid = Nothing Then
tableid = tid
Threading.Thread……
[/Quote]

呃,多个线程同一时间赋值,最终10ms过后,只会有一个线程获得最后的控制权吧,其它线程都得等!
xingyuebuyu 2010-04-16
  • 打赏
  • 举报
回复
Private Sub prodsave(ByVal _name As String, ByVal _link As String)
Do
If tableid = Nothing Then
tableid = tid
Threading.Thread.Sleep(10)
If tableid = tid Then

......
tableid = Nothing
Exit Do
End If
Else
Threading.Thread.Sleep(getrand)
End If

Loop
End Sub


这个样子好像仍然有可能发生问题的.最好还是用LOCK来保证同一时间只有1个THREAD来修改DataTable

http://msdn.microsoft.com/zh-cn/library/3a86s51t(VS.80).aspx

http://msdn.microsoft.com/zh-cn/library/aa712005(VS.71).aspx

http://www.codeproject.com/KB/threads/threadingvbnet.aspx
皇城龙三 2010-04-16
  • 打赏
  • 举报
回复
以前看过一个《白话多线程》的文章,还比较形象,分享给楼主和大家,最后一段是讨论解锁的:

多线程是程序员面试时常常会面对的问题,对多线程概念的掌握和理解水平,也会被一些老鸟用来衡量一个人的编程实力的重要参考指标。不论是实际工作需要还是为了应付面试,掌握多线程都是程序员职业生涯中一个必须经过的环节。其实当你把“多线程”和你的“职业生涯”联系在一起考虑的时候,就会觉得“多线程”是多么的渺小,对,没有跨越不过的山。不过就算它很渺小,但也有可能改变你的人生轨迹。不用担心,如果你对多线程还不太熟悉,那么我们就一起来看看什么是多线程吧。

跟前几篇的风格一样,我会在开篇的时候举一个现实生活中的例子,通过这个例子来映射一些晦涩枯燥的计算机编程专业知识,在让读者朋友很好地理解理论概念的同时,又避免了阅读教科书时的枯燥感觉。这次我要举的例子是公司。不一定是IT公司,尽量和编程领域远一点儿吧,那就假设是一家搬家公司吧。

假如我们把公司看做是一个进程,那么人就是其中的线程。进程必须得有一个主线程,公司在创业初期往往可能出现一人打天下的现象,但是,至少得有一个人,公司才能运作。公司创业初期,业务还不算太多,往往就是老板一个人身兼数职,一天如果只有1、2趟活儿,应该还是忙得过来的。时间长了,随着业务的发展、口碑地建立,生意越来越兴隆,一个人肯定就忙不过来了。假设一天有5个活儿,老板一个人必须搬完A家才能搬B家,搬到黄昏估计也就搬到C家,D和E家都还在焦急地等待着呢。老板一个人要充当搬运工、司机、业务联系人、法人代表、出纳等众多角色,累死累活公司的规模也上不去,人手不够制约了公司的发展。那么怎么办,很简单,增加人手,用编程的话来说就是“再起个线程”。


我们现在就用代码来描述这样的场景吧,首先,我们准备成立一家搬家公司,于是要准备好将来和客户签的合同书:

1: public class Contract   
2: {
3: public string ID { get; private set; }
4: public string From { get; set; }
5: public string To { get; set; }
6: public decimal Fee { get; set; }
7:
8: public Contract()
9: {
10: this.ID = DateTime.Now.ToBinary().ToString().Replace("-", String.Empty);
11: }
12: }

简是简单了点儿,好歹也是份合同,现在我们就去申请注册一家公司,并组建好初创团队,哪怕目前还只有老板一个人:

1: public class HouseMovingCompany
2: {
3: private static HouseMovingCompany _instance = null;
4: public static HouseMovingCompany Instance
5: {
6: get { return (_instance == null ? _instance = new HouseMovingCompany() : _instance); }
7: }
8:
9: public List<Contract> Contracts { get; private set; }
10:
11: public HouseMovingCompany()
12: {
13: this.Contracts = new List<Contract>();
14: }
15:
16: public void MoveHouse()
17: {
18: if (this.Contracts == null || this.Contracts.Count == 0)
19: {
20: return;
21: }
22:
23: Contract contract = contract = this.Contracts[0];
24: this.Contracts.RemoveAt(0);
25:
26: if (!String.IsNullOrEmpty(contract.From) && !String.IsNullOrEmpty(contract.To))
27: {
28: Console.WriteLine("Move the house from {0} to {1}.", contract.From, contract.To);
29: }
30:
31: Thread.Sleep(5000);
32: }
33: }

好了,现在公司实体有了,老板就可以开始忙活了:

1: static void Main(string[] args)
2: {
3: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "WuDaokou", To = "LinDa Road", Fee = 500 });
4:
5: while (HouseMovingCompany.Instance.Contracts.Count > 0)
6: {
7: HouseMovingCompany.Instance.MoveHouse();
8: }
9: }

我们在前面设置了每次搬家耗时5秒钟,咱们把它想象成5个小时。嗯,一天接一个单子,还可以接受,但是随着老板生意日渐兴隆,有时候一天要接3个单子,这就最少要工作15个小时了,还要操心公司的运营等问题,的确忙不过来了,而且照这样算,老板一天不可能完成5个或5个以上的单子,严重制约了公司的发展:

1: static void Main(string[] args)
2: {
3: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "WuDaokou", To = "LinDa Road", Fee = 500 });
4: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "XiDan", To = "WangFujing", Fee = 1000 });
5: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "XiangShan", To = "The Forbidden City", Fee = 10000 });
6:
7: while (HouseMovingCompany.Instance.Contracts.Count > 0)
8: {
9: HouseMovingCompany.Instance.MoveHouse();
10: }
11: }


一天夜里,老板拖着疲倦的身子回到家里,一进门就一头倒在床上,他极力睁着快睁不开的眼睛,努力地对自己说:“不行,我一定要想个办法,不然我会被累死的!”。

其实办法很简单,谁都知道,招聘几个员工,再买几辆车,大家分头行动,不仅分担了工作负担,而且在规模扩大的同时还可以完成更多更大的单子。好,我们现在就借助多线程机制来实现我们的想法:

1: static void Main(string[] args)
2: {
3: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "WuDaokou", To = "LinDa Road", Fee = 500 });
4: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "XiDan", To = "WangFujing", Fee = 1000 });
5: HouseMovingCompany.Instance.Contracts.Add(new Contract { From = "XiangShan", To = "The Forbidden City", Fee = 10000 });
6:
7: Thread thread = null;
8:
9: while (HouseMovingCompany.Instance.Contracts.Count > 0)
10: {
11: thread = new Thread(new ThreadStart(HouseMovingCompany.Instance.MoveHouse));
12:
13: thread.Start();
14: }
15: }

在这段程序中,我们分头行动,让每项搬家任务都由一个小团队去完成,结果我们发现,现在做三个单子的时间跟做一个单子的时间是一样的,提高了效率也扩大了公司规模。但是,既然引入了新的工作机制,我们在公司内部也不得不做一些小小的调整:

1: public void MoveHouse()   
2: {
3: if (this.Contracts == null || this.Contracts.Count == 0)
4: {
5: return;
6: }
7:
8: Contract contract = null;
9:
10: lock (this.Contracts)
11: {
12: contract = this.Contracts[0];
13: this.Contracts.RemoveAt(0);
14: }
15:
16: if (!String.IsNullOrEmpty(contract.From) && !String.IsNullOrEmpty(contract.To)) 17: {
18: Console.WriteLine("Move the house from {0} to {1}.", contract.From,contract.To);
19: }
20:
21: Thread.Sleep(5000);
22: }

调整的只是MoveHouse这个方法内部的一些实现细节。公司接到的单子都保存在Contracts中,所以搬家的时候需要去拿一个单子然后根据单子上的信息来工作。原先我们只有一个线程在操作Contracts,倒也不觉得什么,现在有多个线程都在对Contracts中的元素进行存取,我们不得不提防一些意外发生。这就是在使用多线程的时候常常需要考虑的并发问题,所以我们用了lock关键字,当一个线程要操作Contracts时,它先把Contracts锁起来,其实就是声明一下:“现在我在操作它,你们谁都不要动,等我弄完了再说。”在lock块结束时被锁定的对象才会被解锁,其它的线程现在才可以去操作它。

有了多线程机制,你会发现程序可以在更短的时间内完成更多的事情。本文没有将多线程机制中的所有概念面面俱到地列举出来,但是已经向你展示了该如何使用多线程以及什么时候可以考虑使用多线程,其它的一些细节有待你去进一步探索,例如,你可以设置线程的优先级(假设逻辑上跟Fee挂钩,类似于‘加急’)等等。

掌握多线程机制,并让它使你的应用程序变得更加强悍吧。

hb1122 2010-04-16
  • 打赏
  • 举报
回复
UP一下,看有没碰到过同样问题的!
wiki14 2010-04-16
  • 打赏
  • 举报
回复
沙发之。

16,717

社区成员

发帖
与我相关
我的任务
社区描述
VB技术相关讨论,主要为经典vb,即VB6.0
社区管理员
  • VB.NET
  • 水哥阿乐
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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