分享
 
 
 

在.NET上执行多线程操作要考虑的两大因素

王朝学院·作者佚名  2009-02-04
窄屏简体版  字體: |||超大  

线程管理

线程管理现在变得越来越容易了。在.NET架构中,你可以从线程池中获取线程。线程池是一个生成线程的工厂,如果它已经生成了一定数量的线程且还没有被破坏的话,对它的调用会被阻止。但是,如何确保不会有太多的线程在规定时间内运行?毕竟,如果每个线程能够占用一个CPU核的100%,那么有超过CPU核数量的线程运行,只会导致操作系统启动线程时间分配,这将导致上下文切换和低效率运行。换句话说,同一核上的两个线程不会以两倍的时长完成,可能需要用两倍再加10 %左右的时间来完成。与一个线程相比较的话,三个线程在同一核上想占用100 %的CPU使用率可能会需要3.25——3.5倍的时长来完成。我的经验是,每个核都有多个线程试图占用100 %的CPU,但它们都不能达到目标。

所以,要怎样分配正在运行的线程数量呢?

有一个办法是在线程之间建立一个共享的旗语对象。在线程开始运行前,它会尝试调用旗语的WaitOne模式,并在完成后释放旗语。对CPU的核数量设置旗语限制,(使用EnvironmentProcessorCount功能限定);这将防止您的系统在同一时间运行的线程数多于核数量。与此同时,从线程池中拉出线程将确保您不会在同一时间创建过多线程。如果一次创建线程过多,即使他们并没运行,那也是浪费系统资源。因为每个线程都要消耗资源。使用旗语的一般模式如下所示:

以下为引用的内容:

static Semaphore threadBlocker;

static void Execute(object state)

{ threadBlocker.WaitOne(); //Do work threadBlocker.Release(); }

static void RunThreads()

{ threadBlocker = new Semaphore(0, Environment.ProcessorCount); for (int x = 0; x <= 2000; x++) {ThreadPool.QueueUserWorkItem(new WaitCallback (Execute)); } }

当然还有其他一些办法可以解决这一问题。前一段时间我想要保持对象的一份〈T〉清单。每个对象代表每个工人部件的完整状态。执行和完成时,工人部件都会被填入数据。并且他会设置某个功能以指示任务完成。主线程将扫描对象清单,如果运行的线程数量足够少,就开始运行另一个。说实话,虽然这个方法可行,但对于代码和调试来说这绝对是个噩梦,所以我一点也不推荐。

数据完整性

总体而言,在数据完整性方面,你要担心的问题是竞争条件和死锁。多个线程试图在同一时间更新相同的对象就会造成竞争条件,这将招致麻烦。想象一下如果使用下面这段代码:

以下为引用的内容:

int x = 5;

x = x + 10;

现在,如果线程A和线程B在同一时间运行此代码,将会发生什么情况?它可以运行得很好?还是会出现什么问题?如果出现问题,又是些怎样的问题呢?每个线程都不会一次执行全部语句。因此,我们可以按照以下顺序操作:

以下为引用的内容:

1. Thread A retrieves the value of x (5).

2. Thread B retrieves the value of x (5).

3. Thread A assigns x + 10 (15) to x.

4. Thread B assigns x + 10 (15) to x.

5. x is now equal to 15.

或者,相同的代码可以按照不同的顺序:

以下为引用的内容:

1. Thread A retrieves the value of x (5).

2. Thread A assigned x = 10 (15) to x.

3. Thread B retrieves the value of x (15).

4. Thread B assigns x + 10 (25) to x.

5. x is now equal to 25.

在.NET架构中,最简单也最常见的解决竞争条件的方法是使用“临界区”。而在VB.NET中,该语句是“加锁”,并在C#中是“锁定”,这两种语句都是把对象作为参数。其他尝试锁定相同对象实例使用的临界区(包括上文所指的)会阻止运行直到锁定解除,这样每次就只有一个临界区运行。我们先前举例的一段代码现在看起来是这样的:

以下为引用的内容:

int x = 5;

object lockObject = new object();

Monitor.Enter(lockObject);

x = x + 10;

Monitor.Exit(lockObject);

什么是监控器可以提供而临界区做不到的呢?答案是没有。除非你在解锁后需要更细粒度的控制权。有些复杂的代码可能需要锁定或长或短的一段时间,这都取决于运行的情况,比方一个变量的值。在这种情况下,选择监控器要比需选择临界区更合适。

另一个值得关注的有关数据完整性的问题是死锁。当多个线程锁定资源导致它们都不能够继续运行时,就会出现死锁。例如:

以下为引用的内容:

Thread A:

Monitor.Enter(object1);

Monitor.Enter(object2);

//Do work

Monitor.Exit(object1);

Monitor.Exit(object2);

Thread B:

Monitor.Enter(object2);

Monitor.Enter(object1);

//Do work

Monitor.Exit(object1);

Monitor.Exit(object2);

如果线程A和线程B都调用它们的第一段语句并且同时完成运行,那它们都无法调用它们的第二段语句——这就是一个死锁。所以编写代码的时候细心,要仔细想清楚怎样编写代码才更有利。死锁的发生常见于新手,因为他们过分设置锁定把它变得太详细了。如果代码被嵌套锁定通常表明需要对编写的代码加以认真检查。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有