日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

一起谈.NET技术,.NET并行(多核)编程系列之七 共享数据问题和解决概述

發(fā)布時(shí)間:2025/5/22 asp.net 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一起谈.NET技术,.NET并行(多核)编程系列之七 共享数据问题和解决概述 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  之前的文章介紹了了并行編程的一些基礎(chǔ)的知識(shí),從本篇開(kāi)始,將會(huì)講述并行編程中實(shí)際遇到一些問(wèn)題,接下來(lái)的幾篇將會(huì)講述數(shù)據(jù)共享問(wèn)題。

  本篇的議題如下:

  1.數(shù)據(jù)競(jìng)爭(zhēng)

  2.解決方案提出

  3.順序的執(zhí)行解決方案

  4.數(shù)據(jù)不變解決方案

  在開(kāi)始之前,首先,我們來(lái)看一個(gè)很有趣的例子:

class BankAccount
{
public int Balance
{
get;
set;
}
}
class App
{
static void Main(string[] args)
{
// create the bank account instance
BankAccount account = new BankAccount();
// create an array of tasks
Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++)
{
// create a new task
tasks[i] = new Task(() =>
{
// enter a loop for 1000 balance updates
for (int j = 0; j < 1000; j++)
{
// update the balance
account.Balance = account.Balance + 1;
}
});
// start the new task
tasks[i].Start();
}

// wait for all of the tasks to complete
Task.WaitAll(tasks);

// write out the counter value
Console.WriteLine("Expected value {0}, Counter value: {1}",
10000, account.Balance);

// wait for input before exiting
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}

  10個(gè)task,每個(gè)task都是把BankAccount.Balance自增1000次。之后代碼就等到10個(gè)task執(zhí)行完畢,然后打印出Balance的值。大家猜想一下,上次的代碼執(zhí)行完成之后,打印出來(lái)的Balance的結(jié)果是多少?

  J結(jié)果確實(shí)和大家猜想的一樣:結(jié)果不等于10000。每次執(zhí)行一次上面的代碼,都會(huì)得到不同的結(jié)果,而且這些結(jié)果值都在10000左右,如果運(yùn)氣好,可能看到有那么一兩次結(jié)果為10000.為什么會(huì)這樣?

  下面就是本篇和接下來(lái)的幾篇文章要講述的內(nèi)容。

  1.數(shù)據(jù)競(jìng)爭(zhēng)

  如果大家對(duì)多線程編程比較熟悉,就知道上面情況的產(chǎn)生是因?yàn)?“共享數(shù)據(jù)競(jìng)爭(zhēng)”導(dǎo)致的(對(duì)多線程不熟悉不清楚的朋友也不用擔(dān)心)。當(dāng)有兩個(gè)或者更多的task在運(yùn)行并且操作同一個(gè)共享公共數(shù)據(jù)的時(shí)候,就存在潛在的競(jìng)爭(zhēng)。如果不合理的處理競(jìng)爭(zhēng)問(wèn)題,就會(huì)出現(xiàn)上面意想不到的情況。

  下面就來(lái)分析一下:上面代碼的情況是怎么產(chǎn)生的。

  當(dāng)在把a(bǔ)ccount對(duì)象的Balance進(jìn)行自增的時(shí)候,一般執(zhí)行下面的三個(gè)步驟:

  讀取現(xiàn)在account對(duì)象的Balance屬性的值。

  計(jì)算,創(chuàng)建一個(gè)臨時(shí)的新變量,并且把Balance屬性的值賦值給新的變量,而且把新變量的值增加1

  把新變量的值再次賦給account的Balance屬性

  在理論上面,上面的三個(gè)步驟是代碼的執(zhí)行步驟,但是實(shí)際中,由于編譯器,.NET 運(yùn)行時(shí)對(duì)自增操作的優(yōu)化操作,和操作系統(tǒng)等的因素,在執(zhí)行上面代碼的時(shí)候,并不一定是按照我們?cè)O(shè)想的那樣運(yùn)行的,但是為了分析的方便,我們還是假設(shè)代碼是按照上面的三個(gè)步驟運(yùn)行的。

  之前的代碼每次執(zhí)行一次,執(zhí)行代碼的計(jì)算機(jī)就每次處于不同的狀態(tài):CPU的忙碌狀況不同,內(nèi)存的剩余多少不同,等等,所以每次代碼的運(yùn)行,計(jì)算機(jī)不可能處于完全一樣的環(huán)境中。

  在下面的圖中,顯示了兩個(gè)task之間是如何發(fā)生競(jìng)爭(zhēng)的。當(dāng)兩個(gè)task啟動(dòng)了之后(雖然說(shuō)是并行運(yùn)算,但是不管這樣,兩個(gè)的task的執(zhí)行時(shí)間不可能完全一樣,也就是說(shuō),不可能恰好就是同時(shí)開(kāi)始執(zhí)行的,起碼在開(kāi)始執(zhí)行的時(shí)間上是有一點(diǎn)點(diǎn)的差異的)。

  1. 首先Task1讀取到當(dāng)前的balance的值為0。

  2. 然后,task2運(yùn)行了,并且也讀取到當(dāng)前的balance值為0。

  3. 兩個(gè)task都把balance的值加1

  4. Task1把balance的值加1后,把新的值保存到了balance中

  5. Task2 也把新的保存到了balance中

  所以,結(jié)果就是:雖然兩個(gè)task 都為balance加1,但是balance的值還是1。

  通過(guò)這個(gè)例子,相信大家應(yīng)該清楚,為什么上面的10個(gè)task執(zhí)行1000,而執(zhí)行后的結(jié)果不是10000了。

  2. 解決方案提出

  數(shù)據(jù)競(jìng)爭(zhēng)就好比一個(gè)生日party。其中,每一個(gè)task都是參加party的人,當(dāng)生日蛋糕出來(lái)之后,每個(gè)人都興奮了。如果此時(shí),所有的人都一起沖過(guò)去拿屬于他們自己的那塊蛋糕,此時(shí)party就一團(tuán)糟了,沒(méi)有如何順序。

  在之前的圖示例講解中,balance那個(gè)屬性就好比蛋糕,因?yàn)閠ask1,task2都要得到它,然后進(jìn)行運(yùn)算。當(dāng)我們來(lái)讓多個(gè)task共享一個(gè)數(shù)據(jù)時(shí)就可能出現(xiàn)問(wèn)題。下面列出了四種解決方案:

  1. 順序執(zhí)行:也就是讓第一個(gè)task執(zhí)行完成之后,再執(zhí)行第二個(gè)。

  2. 數(shù)據(jù)不變:我們讓task不能修改數(shù)據(jù)。

  3. 隔離:我們不共享數(shù)據(jù),讓每個(gè)task都有一份自己的數(shù)據(jù)拷貝。

  4. 同步:通過(guò)調(diào)整task的執(zhí)行,有序的執(zhí)行task。

  注意:同步和以前多線程中的同步,或者數(shù)據(jù)庫(kù)操作時(shí)的同步概念不一樣

  3.順序的執(zhí)行的解決方案

  順序的執(zhí)行解決了通過(guò)每次只有一個(gè)task訪問(wèn)共享數(shù)據(jù)的方式解決了數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題,其實(shí)在本質(zhì)上,這種解決方案又回到了之前的單線程編程模型。如果拿之前的party分蛋糕的例子,那么現(xiàn)在就是一次只能允許一個(gè)人去拿蛋糕。

  4.數(shù)據(jù)不變解決方案

  數(shù)據(jù)不變的解決方案就是通過(guò)讓數(shù)據(jù)不能被修改的方式來(lái)解決共享數(shù)據(jù)競(jìng)爭(zhēng)。如果拿之前的蛋糕為例子,那么此時(shí)的情況就是:現(xiàn)在蛋糕只能看,不能吃。

  在C#中,可以同關(guān)鍵字 readonly 和 const來(lái)聲明一個(gè)字段不能被修改:

  public const int AccountNumber=123456;

  被聲明為const的字段只能通過(guò)類(lèi)型來(lái)訪問(wèn):如,上面的AccountNumber是在Blank類(lèi)中聲明的,那么訪問(wèn)的方式就是Blank. AccountNumber

  readonly的字段可以在實(shí)例的構(gòu)造函數(shù)中修改。

  如下代碼:

using System;

class ImmutableBankAccount
{
public const int AccountNumber = 123456;
public readonly int Balance;
public ImmutableBankAccount(int InitialBalance)
{
Balance
= InitialBalance;
}
public ImmutableBankAccount()
{
Balance
= 0;
}
}

class App
{
static void Main(string[] args)
{
// create a bank account with the default balance
ImmutableBankAccount bankAccount1 = new ImmutableBankAccount();
Console.WriteLine(
"Account Number: {0}, Account Balance: {1}",

ImmutableBankAccount.AccountNumber, bankAccount1.Balance);

// create a bank account with a starting balance
ImmutableBankAccount bankAccount2 = new ImmutableBankAccount(200);
Console.WriteLine(
"Account Number: {0}, Account Balance: {1}",
ImmutableBankAccount.AccountNumber, bankAccount2.Balance);

// wait for input before exiting
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}

  數(shù)據(jù)不變的解決方案不是很常用,因?yàn)樗鼘?duì)數(shù)據(jù)限制太大了。

轉(zhuǎn)載于:https://www.cnblogs.com/waw/archive/2011/09/02/2163147.html

總結(jié)

以上是生活随笔為你收集整理的一起谈.NET技术,.NET并行(多核)编程系列之七 共享数据问题和解决概述的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。