生態環境部通報9月和1-9月全國地表水、環境空氣質量狀況_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

2020-10-20 來源:生態環境部

2020-10-20
來源:生態環境部 分享到:
[打印]
字號:[大] [中] [小]   生態環境部今日向媒體通報了2020年9月和1-9月全國地表水、環境空氣質量狀況。   
一、地表水
  (一)總體情況   2020年9月,1940個國家地表水考核斷面中,水質優良(Ⅰ-Ⅲ類)斷面比例為75.9%,同比上升3.9個百分點;劣Ⅴ類斷面比例為2.1%,同比下降1.7個百分點。主要污染指標為總磷、化學需氧量和高錳酸鹽指數。 圖1  2020年9月全國地表水水質類別比例   2020年1-9月,1940個國家地表水考核斷面中,水質優良(Ⅰ~Ⅲ類)斷面比例為81.2%,同比上升6.2個百分點;劣Ⅴ類斷面比例為0.8%,同比下降2.6個百分點。主要污染指標為化學需氧量、總磷和高錳酸鹽指數。 圖2  2020年1-9月全國地表水水質類別比例  
 (二)主要江河水質狀況   2020年9月,長江、黃河、珠江、松花江、淮河、海河、遼河等七大流域及西北諸河、西南諸河和浙閩片河流水質優良(Ⅰ~Ⅲ類)斷面比例為79.5%,同比上升3.4個百分點;劣Ⅴ類斷面比例為1.6%,同比下降1.4個百分點。主要污染指標為化學需氧量、高錳酸鹽指數和總磷。其中,西北諸河、西南諸河和長江流域水質為優,浙閩片河流、黃河和珠江流域水質良好,遼河、海河、淮河和松花江流域為輕度污染。 圖3  2020年9月七大流域和西南、西北諸河及浙閩片河流水質類別比例   2020年1-9月,長江、黃河、珠江、松花江、淮河、海河、遼河等七大流域及西北諸河、西南諸河和浙閩片河流水質優良(Ⅰ~Ⅲ類)斷面比例為84.9%,同比上升6.3個百分點;劣Ⅴ類斷面比例為0.4%,同比下降2.9個百分點。主要污染指標為化學需氧量、高錳酸鹽指數和總磷。其中,西北諸河、長江流域、西南諸河、浙閩片河流和珠江流域水質為優;黃河和松花江流域水質良好;淮河、遼河和海河流域為輕度污染。 圖4  2020年1-9月七大流域和西南、西北諸河及浙閩片河流水質類別比例  
 (三)重要湖(庫)水質狀況及營養狀態   2020年9月,監測的111個重點湖(庫)中,Ⅰ-Ⅲ類水質湖庫個數佔比65.8%,同比上升1.9個百分點;劣Ⅴ類水質湖庫個數佔為4.5%,同比下降2.9個百分點。主要污染指標為總磷、高錳酸鹽指數和化學需氧量。106個監測營養狀態的湖(庫)中,中度富營養的6個,佔5.7%;輕度富營養的26個,佔24.5%;其餘湖(庫)未呈現富營養化。其中,太湖、巢湖為輕度污染、輕度富營養,主要污染指標均為總磷;滇池為中度污染、中度富營養,主要污染指標為化學需氧量、總磷和高錳酸鹽指數;洱海、丹江口水庫水質為優、中營養;白洋淀為輕度污染、輕度富營養,主要污染指標為總磷、化學需氧量和高錳酸鹽指數。與去年同期相比,洱海水質有所好轉、營養狀態無明顯變化,丹江口水庫、白洋淀、太湖、巢湖和滇池水質和營養狀態均無明顯變化。   2020年1-9月,監測的112個重點湖(庫)中,Ⅰ-Ⅲ類水質湖庫個數佔比72.3%,同比上升4.1個百分點;劣Ⅴ類水質湖庫個數佔比5.4%,同比下降1.9個百分點。主要污染指標為總磷、化學需氧量和高錳酸鹽指數。109個監測營養狀態的湖(庫)中,重度富營養的1個,佔0.9%;中度富營養的6個,佔5.5%;輕度富營養的25個,佔22.9%;其餘湖(庫)未呈現富營養化。其中,太湖、巢湖為輕度污染、輕度富營養,主要污染指標均為總磷;滇池為中度污染、中度富營養,主要污染指標為化學需氧量、總磷和高錳酸鹽指數;洱海、丹江口水庫水質為優、中營養;白洋淀為輕度污染、輕度富營養,主要污染指標為化學需氧量、總磷和高錳酸鹽指數。與去年同期相比,洱海水質有所好轉,營養狀態無明顯變化;滇池水質和營養狀態均有所下降;丹江口水庫、太湖、巢湖和白洋淀水質和營養狀態均無明顯變化。  
 (四)地級及以上城市國家地表水考核斷面排名   參加排名的全國地級及以上城市,覆蓋2050個國控斷面(其中1940個為國家地表水考核斷面,110個為入海控制斷面)。2020年9月,全國地級及以上城市中,吐魯番、來賓和柳州市等30個城市國家地表水考核斷面水環境質量相對較好(從第1名至第30名),滄州、東營和邢台市等30個城市國家地表水考核斷面水環境質量相對較差(從倒數第1名至倒數第30名)。1-9月,全國地級及以上城市中,柳州、張掖和金昌市等30個城市國家地表水考核斷面水環境質量相對較好(從第1名至第30名),銅川、滄州和邢台市等30個城市國家地表水考核斷面水環境質量相對較差(從倒數第1名至倒數第30名);營口、呂梁和東莞市等30個城市國家地表水考核斷面水環境質量變化情況相對較好(從第1名至第30名),銅川、常德和赤峰市等30個城市國家地表水考核斷面水環境質量變化情況相對較差(從倒數第1名至倒數第30名)。詳細見附表1~附表6。  
 二、環境空氣    9月,全國337個地級及以上城市平均優良天數比例為91.7%,同比上升11.2個百分點;PM
2.5濃度為21微克/立方米,同比下降19.2%;PM
10濃度為42微克/立方米,同比下降17.6%;O
3濃度為134微克/立方米,同比下降14.6%;SO
2濃度為9微克/立方米,同比下降10.0%;NO
2濃度為22微克/立方米,同比下降8.3%;CO濃度為0.9毫克/立方米,同比持平。   1-9月,全國337個地級及以上城市平均優良天數比例為87.2%,同比上升5.7個百分點;PM
2.5濃度為30微克/立方米,同比下降11.8%;PM
10濃度為51微克/立方米,同比下降15.0%;O
3濃度為142微克/立方米,同比下降6.6%;SO
2濃度為10微克/立方米,同比下降9.1%;NO
2濃度為22微克/立方米,同比下降12.0%;CO濃度為1.2毫克/立方米,同比下降7.7%。 圖5  2020年1-9月全國337個地級及以上城市各級別天數比例 圖6  2020年1-9月全國337個地級及以上城市六項指標濃度及同比變化   9月,京津冀及周邊地區“2+26”城市平均優良天數比例為74.2%,同比上升25.7個百分點;PM
2.5濃度為31微克/立方米,同比下降16.2%;O
3濃度為180微克/立方米,同比下降12.2%。1-9月,平均優良天數比例為62.8%,同比上升13.1個百分點;PM
2.5濃度為48微克/立方米,同比下降11.1%;O
3濃度為189微克/立方米,同比下降6.9%。   北京市9月優良天數比例為90.0%,同比上升40.0個百分點;PM
2.5濃度為24微克/立方米,同比下降33.3%;O
3濃度為151微克/立方米,同比下降29.1%。1-9月,優良天數比例為71.9%,同比上升11.5個百分點;PM
2.5濃度為39微克/立方米,同比下降7.1%;O
3濃度為186微克/立方米,同比下降9.7%。   長三角地區41個城市9月平均優良天數比例為80.2%,同比上升5.7個百分點;PM
2.5濃度為26微克/立方米,同比下降3.7%;O
3濃度為180微克/立方米,同比持平。1-9月,平均優良天數比例為85.4%,同比上升10.2個百分點;PM
2.5濃度為32微克/立方米,同比下降17.9%;O
3濃度為159微克/立方米,同比下降7.0%。   汾渭平原11個城市9月平均優良天數比例為90.6%,同比上升11.5個百分點;PM
2.5濃度為32微克/立方米,同比上升10.3%;O
3濃度為155微克/立方米,同比下降9.4%。1-9月,平均優良天數比例為71.5%,同比上升12.1個百分點;PM
2.5濃度為44微克/立方米,同比下降15.4%;O
3濃度為168微克/立方米,同比下降6.7%。   9月,168個重點城市中,安陽、淄博和唐山市等城市空氣質量相對較差(從倒數第1名至倒數第20名);海口、雅安和貴陽市等城市空氣質量相對較好(從第1名至並列第19名),見附表7。   1-9月,168個重點城市中,唐山、石家莊和太原市等城市空氣質量相對較差(從倒數第1名至倒數第20名);海口、拉薩、珠海市等城市空氣質量相對較好(從第1名至並列第19名),見附表8。包頭、呼和浩特和哈爾濱市等20個城市空氣質量變化情況相對較差(從倒數第1名至並列倒數第20名);宜昌、荊州和荊門市等20個城市空氣質量變化情況相對較好(從第1名至並列第19名),見附表9。   
附表1
2020年9月國家地表水考核斷面水環境質量狀況排名前30位城市及所在水體

排名

城市

考核斷面所在水體

1

吐魯番市

白楊河

2

來賓市

紅水河,黔江,柳江

3

柳州市

洛清江,融江,柳江

4

烏魯木齊市

烏魯木齊河,水磨河

5

和田地區

玉龍喀什河,喀拉喀什河

6

張掖市

黑河,北大河,東大河

7

果洛藏族自治州

黃河

8

桂林市

尋江,甘棠江,夫夷水,桂江,洛清江,灕江,湘江

9

河源市

新豐江水庫,東江

10

金昌市

金川河

11

雲浮市

西江

12

黔東南苗族侗族自治州

都柳江,清水江,沅江,舞水,渠水,巴拉河

13

嘉峪關市

北大河(乾渠)

14

貴港市

潯江,鬱江

15

攀枝花市

雅礱江,金沙江

16

德宏傣族景頗族自治州

大盈江,南畹河,瑞麗江,芒市大河

17

阿克蘇地區

托什干河,阿克蘇河

18

崇左市

左江,明江

19

永州市

湘江,瀟水

20

恩施土家族苗族自治州

溇水,鬱江,長江,清江,唐岩河,酉水

21

昌吉回族自治州

三屯河

22

黃山市

太平湖,練江,新安江,橫江,率水,昌江

23

河池市

龍江,龍岩灘水庫,紅水河

24

肇慶市

西江,北江

25

喀什地區

克孜河,恭弘=叶 恭弘爾羌河,提孜那甫河

26

林芝市

雅魯藏布江

27

防城港市

防城江,北侖河

28

梧州市

西江,賀江,潯江

29

怒江傈僳族自治州

怒江

30

湘西土家族苗族自治州

酉水,峒河,沅江

   
 附表2
2020年9月國家地表水考核斷面水環境質量狀況排名后30位城市及所在水體

 排名

城市

考核斷面所在水體

倒1

滄州市

子牙新河,子牙河,北排河,石碑河,漳衛新河,廖佳窪河,滄浪渠,青靜黃排水渠,南排河,宣惠河

倒2

東營市

挑河,廣利河,神仙溝

倒3

邢台市

衛運河,牛尾河,滏陽河

倒4

鶴壁市

衛河,淇河

倒5

德州市

南運河,徒駭河,德惠新河

倒6

商丘市

包河,惠濟河,澮河,大沙河,沱河

倒7

深圳市

赤石河,茅洲河,深圳河

倒8

煙台市

大沽河,五龍河,沁水河,泳汶河,辛安河,界河,東村河

倒9

濱州市

幸福河*,小清河,黃河,潮河,小米河,馬頰河,支脈河,德惠新河,徒駭河,漳衛新河

倒10

淮北市

澮河,澥河,濉河,沱河

倒11

通遼市

西遼河

倒12

聊城市

高唐湖*,衛運河,馬頰河,徒駭河

倒13

日照市

沭河,付疃河

倒14

無錫市

大港河,長江,新夏港河,百瀆港,新興塘河-九里河,望虞河,梁溪河,殷村港,京杭運河,大浦港,白屈港,太湖

倒15

東莞市

珠江廣州段*,石馬河,茅洲河,東莞運河,東江

倒16

阜新市

西細河

倒17

雞西市

烏蘇里江,穆棱河,松阿察河,小興凱湖,興凱湖

倒18

茂名市

高州水庫*,鑒江,袂花江,關屋河,小東江,寨頭河

倒19

徐州市

徐洪河,大沙河,京杭大運河(不牢河段),沿河,運料河,沭河,復新河,奎河,京杭大運河(中運河段)

倒20

保定市

南拒馬河*,唐河*,拒馬河,府河,白洋淀

倒21

衡水市

滹沱河,衡水湖,滏陽河,清涼江

倒22

天津市

爾王莊水庫*,子牙河*,南水北調天津段*,果河*,引灤天津河,北運河,海河,州河,獨流減河,南運河,子牙新河,洪泥河,潮白新河,永定新河,北排河,於橋水庫,滄浪渠,青靜黃排水渠,薊運河

倒23

昆明市

小江*,陽宗海*,船房河*,金沙江*,寶象河,淤泥河,南盤江,東大河,茨巷河,馬料河,西壩河,金汁河,洛龍河,牛欄江,普渡河,撈漁河,盤龍江,滇池,鳴矣河,大觀河,螳螂川

倒24

呼和浩特市

黃河,渾河,大黑河

倒25

開封市

惠濟河,渦河

倒26

連雲港市

燒香河,青口河,古泊善後河,薔薇河,沙旺河,新沂河,興庄河,車軸河,范河,西鹽大浦河,新沭河,五灌河,淮沭新河,龍王河,灌河,朱稽河,通榆河,大浦河,排淡河

倒27

雙鴨山市

撓力河,安邦河,烏蘇里江

倒28

宿州市

沱河,新濉河,澮河,新汴河

倒29

濮陽市

黃河*,馬頰河,金堤河

倒30

遼源市

東遼河

  注:表中帶*水體水質達到《地表水環境質量標準》(GB3838-2002)Ⅰ類或Ⅱ類。   
附表3
2020年1-9月國家地表水考核斷面水環境質量狀況排名前30位城市及所在水體

排名

城市

考核斷面所在水體

1

柳州市

洛清江,融江,柳江

2

張掖市

黑河,北大河,東大河

3

金昌市

金川河

4

桂林市

甘棠江,湘江,尋江,夫夷水,洛清江,桂江,灕江

5

黔東南苗族侗族自治州

都柳江,清水江,沅江,渠水,舞水,巴拉河

6

吐魯番市

白楊河

7

來賓市

黔江,紅水河,柳江

8

雲浮市

西江

9

攀枝花市

雅礱江,金沙江

10

河池市

紅水河,龍岩灘水庫,龍江

11

貴港市

鬱江,潯江

12

梧州市

西江,賀江,潯江

13

肇慶市

西江,北江

14

河源市

新豐江水庫,東江

15

崇左市

左江,明江

16

昌吉回族自治州

開墾河,三屯河

17

嘉峪關市

北大河(乾渠)

18

永州市

湘江,瀟水

19

玉樹藏族自治州

通天河

20

阿拉善盟

額濟納河

21

昌都市

瀾滄江,怒江,金沙江

22

麗水市

湖南鎮水庫,小溪,好溪,松陰溪,龍泉溪,甌江,大溪,松源溪

23

賀州市

賀江,桂江

24

百色市

澄碧河,難灘河,右江,剝隘河,萬峰湖

25

喀什地區

恭弘=叶 恭弘爾羌河,克孜河,提孜那甫河

26

昭通市

牛欄江,橫江,赤水河,頭屯河,金沙江

27

雅安市

大渡河,青衣江

28

甘孜藏族自治州

金沙江,大渡河

29

黔南布依族苗族自治州

濛江,都柳江,清水江,重安江,樟江,紅水河,羊昌河

30

黃山市

太平湖,練江,新安江,率水,橫江,昌江

 
 附表4
2020年1-9月國家地表水考核斷面水環境質量狀況排名后30位城市及所在水體

排名

城市

考核斷面所在水體

倒1

銅川市

石川河

倒2

滄州市

子牙河,滄浪渠,子牙新河,石碑河,廖佳窪河,漳衛新河,宣惠河,青靜黃排水渠,南排河,北排河

倒3

邢台市

牛尾河,衛運河,滏陽河

倒4

東營市

挑河,神仙溝,廣利河

倒5

濱州市

黃河*,幸福河*,德惠新河,小米河,小清河,支脈河,徒駭河,漳衛新河,潮河,馬頰河

倒6

阜新市

西細河

倒7

日照市

沭河,付疃河

倒8

商丘市

包河,惠濟河,澮河,沱河,大沙河

倒9

濰坊市

濰河,虞河,白浪河,峽山水庫,彌河,小清河,北膠萊河

倒10

瀋陽市

渾河,拉馬河,柳河,蒲河,遼河,細河

倒11

遼源市

東遼河

倒12

淮北市

濉河,澮河,澥河,沱河

倒13

呂梁市

嵐漪河*,黃河*,屈產河,文峪河,三川河,湫水河,磁窯河,嵐河,蔚汾河

倒14

臨汾市

沁河*,昕水河,汾河,澮河

倒15

廊坊市

龍河*,北運河,潮白河,子牙河,泃河,潮白新河,大清河

倒16

天津市

南水北調天津段*,南運河*,爾王莊水庫*,子牙河*,北運河*,於橋水庫,引灤天津河,洪泥河,果河,州河,海河,潮白新河,永定新河,滄浪渠,獨流減河,北排河,子牙新河,青靜黃排水渠,薊運河

倒17

通遼市

西遼河

倒18

連雲港市

車軸河,范河,新沭河,青口河,龍王河,淮沭新河,灌河,朱稽河,通榆河,新沂河,薔薇河,沙旺河,興庄河,燒香河,西鹽大浦河,五灌河,古泊善後河,大浦河,排淡河

倒19

鶴壁市

淇河,衛河

倒20

淄博市

沂河*,小清河

倒21

青島市

嶗山水庫,李村河,吉利河,風河,墨水河,白沙河,大沽河,海泊河,北膠萊河

倒22

宿州市

新汴河,沱河,新濉河,澮河

倒23

盤錦市

繞陽河,大遼河,遼河

倒24

徐州市

沭河,復新河,京杭大運河(不牢河段),大沙河,徐洪河,京杭大運河(中運河段),沿河,運料河,奎河

倒25

四平市

東遼河,招蘇台河,條子河,西遼河

倒26

延安市

北洛河,王瑤水庫,延河,仕望河,清澗河

倒27

宿遷市

京杭大運河(中運河段)*,徐洪河,柴米河,溧河,駱馬湖,老汴河,洪澤湖

倒28

煙台市

大沽河*,黃水河,辛安河,大沽夾河,界河,泳汶河,五龍河,東村河,沁水河

倒29

菏澤市

新萬福河,洙趙新河,東漁河

倒30

玉溪市

撫仙湖*,元江*,曲江,南盤江,星雲湖,杞麓湖

  注:表中帶*水體水質達到《地表水環境質量標準》(GB3838-2002)Ⅰ類或Ⅱ類。   附表5 2020年1-9月國家地表水考核斷面水環境質量變化情況排名前30位城市及所在水體

排名

城市

變化幅度

考核斷面所在水體

1

營口市

-73.42%

碧流河,大清河,熊岳河,沙河,大遼河,大旱河

2

呂梁市

-64.82%

嵐漪河,黃河,屈產河,文峪河,三川河,磁窯河,湫水河,嵐河,蔚汾河

3

東莞市

-45.29%

珠江廣州段,茅洲河,東莞運河,石馬河,東江

4

晉中市

-44.88%

清漳河,松溪河,瀟河,汾河

5

茂名市

-39.47%

高州水庫,關屋河,鑒江,袂花江,寨頭河,小東江,森高河

6

惠州市

-38.97%

西枝江,柏崗河,東江,增江,岩前河,霞涌河,淡水河,沙河,南邊灶河,吉隆河,淡澳河

7

遼源市

-38.31%

東遼河

8

太原市

-37.96%

汾河

9

臨汾市

-34.97%

沁河,昕水河,汾河,澮河

10

廊坊市

-33.49%

龍河,北運河,潮白河,子牙河,泃河,潮白新河,大清河

11

邢台市

-31.64%

牛尾河,衛運河,滏陽河

12

烏蘭察布市

-30.52%

大黑河,御河

13

普洱市

-30.50%

南拉河,李仙江,南馬河,瀾滄江,威遠江,思茅河

14

阜新市

-30.16%

西細河

15

博爾塔拉蒙古自治州

-30.11%

賽里木湖,艾比湖

16

聊城市

-30.10%

高唐湖,衛運河,馬頰河,徒駭河

17

鞍山市

-29.62%

哨子河,大洋河,海城河,太子河,遼河

18

慶陽市

-28.91%

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

蒲河,馬蓮河

19

安陽市

-28.62%

淅河,淇河,露水河,安陽河,衛河

20

怒江傈僳族自治州

-28.31%

怒江

21

錦州市

-28.30%

女兒河,大凌河,小凌河,龐家河

22

深圳市

-28.10%

赤石河,深圳河,茅洲河

23

朔州市

-27.60%

桑乾河,蒼頭河

24

盤錦市

-27.57%

繞陽河,大遼河,遼河

25

延安市

-26.43%

北洛河,王瑤水庫,延河,仕望河,清澗河

26

陽泉市

-24.51%

滹沱河,綿河,桃河

27

武威市

-23.16%

黃羊河,石羊河,紅崖山水庫

28

大連市

-22.62%

碧流河,英那河,登沙河,復州河,庄河,大沙河

29

四平市

-20.53%

東遼河,招蘇台河,條子河,西遼河

30

巴中市

-20.49%

巴河

 
 附表6
2020年1-9月國家地表水考核斷面水環境質量變化情況排名后30位城市及所在水體

排名

城市

變化幅度

考核斷面所在水體

倒1

銅川市

20.19%

石川河

倒2

常德市

7.95%

沅江*,澧水*,洞庭湖

倒3

赤峰市

7.67%

老虎山河*,西拉木淪河,老哈河,烏爾吉沐淪河

倒4

漳州市

6.70%

東溪,西溪,花山溪,九龍江,漳江,龍津溪,南溪

倒5

大慶市

5.52%

松花江,嫩江

倒6

自貢市

4.69%

越溪河,沱江,釜溪河

倒7

淄博市

4.69%

沂河*,小清河

倒8

濱州市

4.35%

黃河*,幸福河*,德惠新河,小米河,小清河,支脈河,徒駭河,漳衛新河,潮河,馬頰河

倒9

湛江市

3.87%

鶴地水庫,南渡河,雷州青年運河,鑒江,袂花江,九洲江

倒10

海口市

3.68%

南渡江*,文昌河,演州河

倒11

紅河哈尼族彝族自治州

3.52%

南溪河*,紅河*,藤條江*,小河底河,南盤江,異龍湖

倒12

宿遷市

3.26%

京杭大運河*,徐洪河,柴米河,溧河,駱馬湖,老汴河,洪澤湖

倒13

莆田市

2.77%

木蘭溪,萩蘆溪

倒14

上饒市

2.72%

饒河*,洎水河*,樂安河*,昌江*,信江*,信江西支*,鄱陽湖

倒15

雙鴨山市

2.59%

撓力河,烏蘇里江,安邦河

倒16

杭州市

2.08%

新安江*,分水江*,富春江*,東苕溪*,浦陽江*,錢塘江*,千島湖*,京杭運河,西湖

倒17

商丘市

0.87%

包河,惠濟河,澮河,沱河,大沙河

倒18

東營市

0.85%

挑河,神仙溝,廣利河

倒19

徐州市

0.68%

沭河,復新河,京杭大運河(不牢河段),徐洪河,大沙河,沿河,京杭大運河(中運河段),運料河,奎河

倒20

揭陽市

0.37%

龍江,榕江南河,榕江北河

倒21

汕尾市

0.35%

螺河*,烏坎河,黃江河

倒22

威海市

-0.06%

黃壘河*,乳山河*,沽河,母豬河

倒23

淮北市

-0.31%

濉河,澮河,澥河,沱河

倒24

中山市

-0.62%

洪奇瀝水道*,磨刀門水道*,橫門水道*,中心河,蘭溪河,泮沙排洪渠

倒25

濟南市

-0.72%

黃河*,牟汶河*,玉符河*,瀛汶河,小清河

倒26

台州市

-0.81%

長潭水庫*,里石門水庫*,始豐溪*,永安溪*,海游溪,永寧江,江廈大港,椒江,金清港

倒27

內江市

-1.77%

沱江,威遠河,球溪河

倒28

包頭市

-2.10%

黃河*,昆河,四道沙河

倒29

濟寧市

-2.11%

京杭大運河,老萬福河,東漁河,南四湖,西支河,老運河,洙水河,光府河,泉河,洙趙新河,白馬河,泗河

倒30

滁州市

-2.35%

襄河,滁河,清流河,池河,白塔河,淮河,來河

  注:表中帶*水體水質達到《地表水環境質量標準》(GB3838-2002)Ⅰ類或Ⅱ類。  
 附表7
2020年9月168個重點城市排名前20位和后20位城市名單

前20位

后20位

排名

城市

排名

城市

1

海口市

倒1

安陽市

2

雅安市

倒2

淄博市

3

貴陽市

倒3

唐山市

4

拉薩市

倒4

邯鄲市

5

舟山市

倒5

棗莊市

6

內江市

倒6

晉城市

7

遂寧市

倒7

臨汾市

8

資陽市

倒8

鶴壁市

9

張家口市

倒9

焦作市

9

黃山市

倒10

濟南市

11

昆明市

倒11

臨沂市

12

綿陽市

倒12

太原市

13

德陽市

倒13

徐州市

14

珠海市

倒14

渭南市

15

樂山市

倒15

咸陽市

16

深圳市

倒16

聊城市

17

長春市

倒16

泰安市

18

哈爾濱市

倒18

洛陽市

19

南充市

倒19

衡水市

19

廣安市

倒20

鄭州市

19

福州市

 

 
 附表8
2020年1-9月168個重點城市排名前20位和后20位城市名單

前20位

后20位

排名

城市

排名

城市

1

海口市

倒1

唐山市

2

拉薩市

倒2

石家莊市

3

珠海市

倒3

太原市

4

深圳市

倒4

安陽市

5

黃山市

倒5

臨汾市

6

廈門市

倒6

邢台市

7

中山市

倒7

邯鄲市

8

舟山市

倒8

淄博市

9

麗水市

倒8

包頭市

10

惠州市

倒10

焦作市

11

貴陽市

倒10

晉城市

12

福州市

倒12

鶴壁市

13

江門市

倒13

陽泉市

14

南寧市

倒14

運城市

14

肇慶市

倒15

咸陽市

16

台州市

倒15

濟南市

17

雅安市

倒17

渭南市

18

咸寧市

倒18

保定市

19

昆明市

倒19

西安市

19

東莞市

倒20

聊城市

 
 附表9
2020年1-9月168個重點城市空氣改善幅度排名前20位和后20位城市名單

前20位

后20位

排名

城市

排名

城市

1

宜昌市

倒1

包頭市

2

荊州市

倒2

呼和浩特市

3

荊門市

倒3

哈爾濱市

4

池州市

倒4

長春市

5

常德市

倒5

德陽市

6

中山市

倒6

蘭州市

7

武漢市

倒7

成都市

8

益陽市

倒8

瀋陽市

9

珠海市

倒9

承德市

9

湘潭市

倒10

亳州市

11

株洲市

倒11

唐山市

12

佛山市

倒12

錦州市

13

東莞市

倒12

自貢市

14

安慶市

倒14

渭南市

15

肇慶市

倒15

太原市

15

襄陽市

倒15

廊坊市

17

江門市

倒17

忻州市

17

洛陽市

倒18

西安市

19

孝感市

倒19

眉山市

19

南陽市

倒20

鶴壁市

 

 

倒20

運城市

 

 

倒20

滄州市

 

 

倒20

朔州市

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

全球適應中心理事會第二次會議召開 生態環境部部長黃潤秋視頻講話_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

2020-10-26

2020-10-26
分享到:
[打印]
字號:[大] [中] [小]

  10月23日,全球適應中心理事會第二次會議以視頻方式召開,理事會主席、原聯合國秘書長潘基文和荷蘭皇家帝斯曼集團榮譽主席菲克·謝白曼在線致辭,近20位理事會成員出席視頻會議。生態環境部部長黃潤秋應邀為會議錄製視頻講話。

  黃潤秋表示,面對新冠肺炎疫情帶來的困難和挑戰,全球適應中心积極開展工作,發布《關於新冠肺炎疫情背景下氣候韌性復蘇的行動倡議》、非洲提升氣候韌性的政策簡報,成立南亞區域、非洲區域辦公室,持續推動具體適應合作,為推動各國協同推進疫情后經濟復蘇和增強適應行動、提升全球氣候韌性發揮了积極作用。中方對此表示讚賞。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

  黃潤秋強調,中國為抗擊新冠肺炎疫情付出巨大努力,在取得抗擊疫情鬥爭重大戰略成果的同時,中國一以貫之高度重視、积極開展應對氣候變化工作。習近平主席在第七十五屆聯合國大會一般性辯論上鄭重宣布,中國將提高國家自主貢獻力度,二氧化碳排放力爭於2030年前達到峰值,努力爭取2060年前實現碳中和。中國正在編製《國家適應氣候變化戰略2035》,進一步統籌強化國內適應氣候變化工作,全面提高氣候風險抵禦能力。

  黃潤秋指出,中方支持全球適應中心建設成為全球範圍內具有重要影響力和領導力的適應平台,贊同聚焦非洲提升氣候脆弱和敏感地區韌性、加強適應知識分享與提升、拓展合作夥伴關係等計劃。希望全球適應中心中國辦公室進一步發揮橋樑紐帶作用,在傳播適應知識、促進交流互鑒、分享中國案例等方面提供有效支持。

  據悉,全球適應中心理事會旨在提出前瞻性的適應氣候變化戰略願景,促進大規模、變革性的適應行動和夥伴關係,以推動全球提升適應能力、實現可持續發展目標,並對全球適應中心的工作進行戰略指導。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

五部門聯合召開“美麗中國,我是行動者”主題實踐活動總結會_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

2020-11-05 來源:生態環境部

2020-11-05
來源:生態環境部 分享到:
[打印]
字號:[大] [中] [小]

  11月5日,生態環境部、中央文明辦、教育部、共青團中央、全國婦聯等五部門聯合召開會議,總結“美麗中國,我是行動者”主題實踐活動成果,研究部署下一階段工作。生態環境部副部長庄國泰出席會議並講話。

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

  會議指出,生態環境領域宣傳和動員是黨的宣傳思想工作的重要組成部分。三年來,各部門各條戰線堅持以習近平新時代中國特色社會主義思想和習近平生態文明思想為指引,积極開展“美麗中國,我是行動者”主題實踐活動,生態文明建設主旋律持續高昂,生態環境保護正能量廣泛傳播,生態環境輿論主動局面更加強化,公眾參与環境保護渠道不斷拓展,全社會共建美麗中國熱情顯著提升,生態環境宣傳工作大格局初步形成,為打贏污染防治攻堅戰、建設美麗中國營造了良好社會氛圍。

  會議強調,黨的十九屆五中全會明確提出“十四五”和2035年生態文明建設和生態環境保護的目標任務,要圍繞大力宣傳習近平生態文明思想這一核心任務,持續深入開展“美麗中國,我是行動者”主題實踐活動,努力提升宣傳和動員工作能力和水平,着力推動構建生態環境治理全民行動體系。要深化重大理論研究宣傳,持續推進新聞宣傳,創新開展社會宣傳,不斷改進新媒體宣傳,穩步加強環境教育,推動形成人人關心、支持、參与生態環境保護的工作局面,為建設美麗中國夯實穩固社會基礎。

  中央文明辦、教育部、共青團中央、全國婦聯有關同志作了發言,江蘇、重慶、四川、內蒙古以及福建廈門、浙江湖州等6個地方代表進行經驗交流。

  會議以視頻形式召開,在生態環境部機關設主會場,在各省、市、縣生態環境部門及有關單位設3850個分會場,共14480人參加會議。

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

沒錯 Facebook 又改版了,差在哪你看得出來嗎?_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

這世界上有蠻多事情都有機會阻止甚至是逆轉,但 Facebook 似乎想讓我們知道,他們的改版不僅一定改,而且還會一直改。眼看大家還在適應剛改變的新版 Facebook,這次官方又再次宣布將會有重新設計的調整,魔爪則是伸向了粉絲專頁。繼續閱讀沒錯 Facebook 又改版了,差在哪你看得出來嗎?報導內文。

▲圖片來源:Facebook

沒錯 Facebook 又改版了,差在哪你看得出來嗎?

也許是看到了許多人對於新版粉絲專頁變難用的抱怨。總之,Facebook 已經捲起袖子要來做出改變。根據官方的改版要點整理,粉絲專頁的新設計將會更簡潔直覺,讓人更容易掌握專頁的資訊,也可以更快速切換個人檔案與粉絲專頁。

Facebook 還為粉絲專頁提供了專屬的動態消息 News Feed,讓人更容易在專頁上加入對話與追蹤趨勢加強社群之間互動的機會(這看起來就是將快速跟隨的功能再延伸提供…),並會讓知名人物的評論更容易置頂 — 這的確是比較能吸引其他粉絲互動是沒錯啦。

▲圖片來源:Facebook

應該也算是粉絲專頁的版面調整之一。就是近期已經更為偏重希望使用者多「追蹤(Follow)」的政策與功能,已經導致很多粉絲頁變成追蹤數大於讚數的狀況。現在 Facebook 也移除了按讚的孤能,也讓專頁只主要顯示追蹤數字。據說這樣是希望簡化與互動的方式… 但大家狂衝的讚數似乎也突然變得無意義起來了。

▲圖片來源:Facebook

最後,在一波看不太出來的改版之後,Facebook 也針對變得難用的粉絲專頁管理工具做出改進。針對頁面小編的權限提供了更好的權限管理工具 — 可針對廣告、內容、回訊的資格進行分別設定,也改進了通知功能,並加入新的問答頁面與安全功能等。

整體來講,這次的改版理論上應該是要讓觸及互動等表現更好,粉絲專頁的管理也會變得更為簡單才是。只是實際表現如何,顯然還有待台灣這邊開始更新才會知道了 — 據說會在未來幾週內更新(怕.mov)。

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

引用來源

延伸閱讀:

IKEA 直接賣「家」了,來看看這既環保又有型的 Tiny Home 小屋拖車

傳超值款 iPad(第九代)將更薄更輕且依然有指紋辨識,至於 iPad Pro…

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

蘋果 AirTags 防丟追蹤器還沒出,但已有皮革鑰匙圈與眼鏡環三方配件照流出_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

雖說蘋果的防丟失裝置 AirTags 還沒正式推出,不過目前看來就連副廠配件商也已經備戰中。至於為什麼我們會知道,當然是因為產品照已經被爆料出來啦(笑)。繼續閱讀蘋果 AirTags 防丟追蹤器還沒出,但已有皮革鑰匙圈與眼鏡環三方配件照流出報導內文。

▲圖片來源:Voice

蘋果 AirTags 防丟追蹤器還沒出,但已有皮革鑰匙圈與眼鏡環三方配件照流出

如果有常在注意 Apple 皮革配件產品的朋友,應該都不會對 Nomad 感到太陌生。他們時常針對 iPhone / MacBook 等裝置推出質感不輸原廠的相應保護殼與保護套配件。現在,則是被爆料大神 Evan Bless 給發現,他們已經為 Apple 可能就要推出的 AirTags 藍牙追蹤裝置打造了相關配件。

▲圖片來源:Voice

為了這樣的防丟失產品,Nomad 也設計了與原廠先前流出的配件基本相同功能的鑰匙圈保護套。有意思的是,相對於原廠的圓形造型,Nomad 的皮革鑰匙圈則是方形的設計。然而當我們還在思索這到底是不是為 AirTags 所設計的配件的時候,第二張爆料的眼鏡固定環就巧妙地在調整鬆緊度的圓形機制上,加入了可塞進 AirTags 的空間。

▲圖片來源:Voice

目前看來 AirTags 應該是個功能與 Tile 功能類似,但可能導入 U1 超寬頻晶片來提供更好掌握方向定位的尋物方式。具體的應用似乎也是以盡可能輕便能裝在隨身物品上,藉此在不小心丟失物品時可以起到尋物功能的方向。

▲圖片來源:MacRumors

雖說這並不算什麼新功能,不過相信蘋果只要推出,周邊的各種配件商的一波跟進,將會激盪出不少創新的應用方式吧?

本篇圖片 / 引用來源

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

延伸閱讀:

蘋果 App Store 突破 2 千億美金收益,Apple Music 與 Apple TV 也創新紀錄

沒錯 Facebook 又改版了,差在哪你看得出來嗎?

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

微軟將推出對使用者更友善、更容易使用的檔案恢復工具_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

人嘛!難免有錯手刪掉不該刪檔案的時候,在 2020 年初時,Microsoft 發表了一個供 Windows 系統恢復檔案的工具,允許用戶反會撤銷決定,恢復從各地永久刪除的檔案,包括資源回收桶。雖然這是個福音,但對於大多數用戶來說還是有不算低的門檻,不過接下來,Microsoft 將讓它變得更友善、更容易使用。

微軟將推出對使用者更友善、更容易使用的檔案恢復工具

在之前推出的 Windows 檔案恢復工具,其實是一個指令工具,它的工作方式與其他第三方應用不太一樣,只能輸入指令來使用它,雖說是免費使用,但因為對使用者友好程度低,使得這個工具立意良善卻普及度不如預期。根據消息,Microsoft 有計畫讓這工具的使用更加簡單,新的改良正在路上。

這項工具目前已經對測試人員釋出,根據 Windows Latest 報導,在最新測試版本中除了速度變得更快,還支援一般與廣泛兩種模式。使用新的「一般」模式,你可以掃描磁碟機 (NTFS 檔案系統) 以尋找被刪除檔案並嘗試還原。Microsoft 指出,一般模式是使用者的標準恢復選項,適用於恢復近期刪除的檔案。任何具備一點指令基本知識的人都能夠恢復他們的檔案,雖然一般模式對使用者更友好,但如果硬碟中的可用空間已經被其他檔案所覆蓋,它可能就失去作用了,尤其是如果你的電腦中是使用 SSD 的話。

Microsoft 表示,從 2020 年首度發表檔案恢復工具以來,陸續收到許多使用者的意見回饋,未來幾個月內,該工具將會推出更多改良,第一個大更新會在 2021 年初與 Windows 10 2004 更新或更新的版本推出給普羅大眾。

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

◎資料來源:Windows Latest

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

ClickHouse源碼筆記1:聚合函數的實現_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

由於工作的需求,後續筆者工作需要和開源的OLAP數據庫ClickHouse打交道。ClickHouse是Yandex在2016年6月15日開源了一個分析型數據庫,以強悍的單機處理能力被稱道
筆者在實際測試ClickHouse和閱讀ClickHouse的源碼過程之中,對”戰鬥民族”開發的數據庫十分欣賞。ClickHouse不僅是一個很好的數據庫學習材料,而且同時應用了大量的CPP17的新特性進行開發,也是一個大型的Modern CPP的教導資料。
筆者接下來會陸續將閱讀ClickHouse的部分心得體會與通過源碼閱讀筆記的方式和大家分享,坦白說,這種源碼閱讀筆記很難寫啊。(多一分繁瑣,少一分就模糊了~~)
第一篇文章,我們就從聚合函數的實現開始聊起~~ 上車!

1.基礎知識的梳理

什麼是聚合函數?

聚合函數: 顧名思義就是對一組數據執行聚合計算並返回結果的函數。
這類函數在數據庫之中很常見,如:count, max, min, sum等等。

ClickHouse的實現接口
  • IAggregateFunction接口
    在ClickHouse之中,定義了一個統一的聚合函數接口:IAggregateFunction.(在ClickHouse之中,所有的接口類都是以大寫的I開頭的。) 上文筆者提到的聚合函數,則都是作為抽象類IAggregateFunction的子類實現的。其中該接口最為核心的方法是下面這5個方法:
    • add函數:最為核心的調用接口,將對應AggregateDataPtr指針之中數據取出,與列columns中的第row_num的數據進行對應的聚合計算。(這裏可以看到ClickHouse是一個純粹的列式存儲數據庫,所有的操作都是基於列的數據結構。)
    • merge函數:將兩個聚合結果進行合併的函數,通常用在併發執行聚合函數的過程之中,需要將對應的聚合結果進行合併。
    • serialize函數與deserialize函數:序列化與反序列化的函數,通常用於spill to disk或分佈式場景需要保存或傳輸中間結果的。
    • addBatch函數:這是函數也是非常重要的,雖然它僅僅實現了一個for循環調用add函數。它通過這樣的方式來減少虛函數的調用次數,並且增加了編譯器內聯的概率。(虛函數的調用需要一次訪存指令,一次查表,最終才能定位到需要調用的函數上,這在傳統的火山模型的實現上會帶來極大的CPU開銷。
  /** Adds a value into aggregation data on which place points to.
     *  columns points to columns containing arguments of aggregation function.
     *  row_num is number of row which should be added.
     *  Additional parameter arena should be used instead of standard memory allocator if the addition requires memory allocation.
     */
    virtual void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena) const = 0;

    /// Merges state (on which place points to) with other state of current aggregation function.
    virtual void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena * arena) const = 0;

    /// Serializes state (to transmit it over the network, for example).
    virtual void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const = 0;

    /// Deserializes state. This function is called only for empty (just created) states.
    virtual void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena * arena) const = 0;
    // /** Contains a loop with calls to "add" function. You can collect arguments into array "places"
      *  and do a single call to "addBatch" for devirtualization and inlining.
      */
    virtual void addBatch(size_t batch_size, AggregateDataPtr * places, size_t place_offset, const IColumn ** columns, Arena * arena) const = 0;

  • 抽象類IColumn
    上面的接口IAggregateFunction的函數使用到了ClickHouse的核心接口IColumn類,這裏也進行簡要的介紹。 IColumn 接口表達了所有數據在ClickHouse之中的用內存表達的數據結構,其他帶有具體數據類型的如ColumnUInt8、ColumnArray 等, 都實現了對應的列接口,並且在子類之中具象實現了不同的內存布局。
    IColumn的子類實現細節很瑣碎,筆者這裏就暫時不展開講了,筆者這裏就簡單講講涉及到聚合函數調用部分的IColumn接口的對應方法:
    這裏columns是一個二維數組,通過columns[0]可以取到第一列。(這裏只有涉及到一列,為什麼columns是二維數組呢?因為處理array等列的時候,也是通過對應的接口,而array就需要應用二維數組了. )
    注意這裡有一個強制的類型轉換,column已經轉換為ColVecType類型了,這是模板派生出IColumn的子類。
    然後通過IColumn子類實現的getData方法獲取對應row_num行的數據進行add函數調用就完成了一次聚合函數的計算了。
    void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override
    {
        const auto & column = static_cast<const ColVecType &>(*columns[0]);
        this->data(place).add(column.getData()[row_num]);
    }
  • IAggregateFunctionHelper接口
    這個接口是上面提到 IAggregateFunction的輔助子類接口,它很巧妙的通過模板的類型派生,將虛函數的調用轉換為函數指針的調用,這個在實際聚合函數的實現過程之中能夠大大提高計算的效率。
    函數addFree就實現了我上述所說的過程,但是它是一個private的函數,所以通常我們都是通過getAddressOfAddFunction獲取對應的函數地址。這在聚合查詢的過程之中能夠提高20%左右的執行效率。
template <typename Derived>
class IAggregateFunctionHelper : public IAggregateFunction
{
private:
    static void addFree(const IAggregateFunction * that, AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena * arena)
    {
        static_cast<const Derived &>(*that).add(place, columns, row_num, arena);
    }

public:
    IAggregateFunctionHelper(const DataTypes & argument_types_, const Array & parameters_)
        : IAggregateFunction(argument_types_, parameters_) {}

    AddFunc getAddressOfAddFunction() const override { return &addFree; }
  • AggregateFunctionFactory類
    顧名思義,這個是一個生成聚合函數的工廠類。它的邏輯很簡單,所有ClickHouse之中所相關的聚合函數都是通過這個工廠類註冊並且獲取,然後進行調用的。
class AggregateFunctionFactory final : private boost::noncopyable, public IFactoryWithAliases<AggregateFunctionCreator>
{
public:

    static AggregateFunctionFactory & instance();

    /// Register a function by its name.
    /// No locking, you must register all functions before usage of get.
    void registerFunction(
        const String & name,
        Creator creator,
        CaseSensitiveness case_sensitiveness = CaseSensitive);

    /// Throws an exception if not found.
    AggregateFunctionPtr get(
        const String & name,
        const DataTypes & argument_types,
        const Array & parameters = {},
        int recursion_level = 0) const;

2.聚合函數的註冊流程

有了上述的背景知識,我們接下來舉個栗子。來看看一個聚合函數的實現細節,以及它是如何被使用的。

AggregateFunctionSum

筆者這裏選取了一個很簡單的聚合算子Sum,我們來看看它實現的代碼細節。
這裏我們可以看到AggregateFunctionSum是個final類,無法被繼承了。而它繼承了上面提到的IAggregateFunctionHelp類的子類IAggregateFunctionDataHelper類。

這裏我們就重點看,這個類override了getName方法,返回了對應的名字sum。並且實現了我們上文提到的四個核心的方法。

  • add
  • merge
  • seriable
  • deserialize
template <typename T, typename TResult, typename Data>
class AggregateFunctionSum final : public IAggregateFunctionDataHelper<Data, AggregateFunctionSum<T, TResult, Data>>
{
public:
    using ResultDataType = std::conditional_t<IsDecimalNumber<T>, DataTypeDecimal<TResult>, DataTypeNumber<TResult>>;
    using ColVecType = std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<T>, ColumnVector<T>>;
    using ColVecResult = std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<TResult>, ColumnVector<TResult>>;

    String getName() const override { return "sum"; }

    AggregateFunctionSum(const DataTypes & argument_types_)
        : IAggregateFunctionDataHelper<Data, AggregateFunctionSum<T, TResult, Data>>(argument_types_, {})
        , scale(0)
    {}

    AggregateFunctionSum(const IDataType & data_type, const DataTypes & argument_types_)
        : IAggregateFunctionDataHelper<Data, AggregateFunctionSum<T, TResult, Data>>(argument_types_, {})
        , scale(getDecimalScale(data_type))
    {}

    DataTypePtr getReturnType() const override
    {
        if constexpr (IsDecimalNumber<T>)
            return std::make_shared<ResultDataType>(ResultDataType::maxPrecision(), scale);
        else
            return std::make_shared<ResultDataType>();
    }

    void add(AggregateDataPtr place, const IColumn ** columns, size_t row_num, Arena *) const override
    {
        const auto & column = static_cast<const ColVecType &>(*columns[0]);
        this->data(place).add(column.getData()[row_num]);
    }

    void merge(AggregateDataPtr place, ConstAggregateDataPtr rhs, Arena *) const override
    {
        this->data(place).merge(this->data(rhs));
    }

    void serialize(ConstAggregateDataPtr place, WriteBuffer & buf) const override
    {
        this->data(place).write(buf);
    }

    void deserialize(AggregateDataPtr place, ReadBuffer & buf, Arena *) const override
    {
        this->data(place).read(buf);
    }

    void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
    {
        auto & column = static_cast<ColVecResult &>(to);
        column.getData().push_back(this->data(place).get());
    }

private:
    UInt32 scale;
};

接下來,ClickHouse實現了兩種聚合計算:AggregateFunctionSumDataAggregateFunctionSumKahanData。後者是用Kahan算法避免float類型精度損失的,我們可以暫時不細看。直接看SumData的實現。這是個模板類,之前我們講到AggregateFunction的函數就是通過AggregateDataPtr指針來獲取AggregateFunctionSumData的地址,來調用add實現聚合算子的。我們可以看到AggregateFunctionSumData實現了前文提到的add, merge, write,read四大方法,正好和接口一一對應上了。

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

template <typename T>
struct AggregateFunctionSumData
{
    T sum{};

    void add(T value)
    {
        sum += value;
    }

    void merge(const AggregateFunctionSumData & rhs)
    {
        sum += rhs.sum;
    }

    void write(WriteBuffer & buf) const
    {
        writeBinary(sum, buf);
    }

    void read(ReadBuffer & buf)
    {
        readBinary(sum, buf);
    }

    T get() const
    {
        return sum;
    }
};

ClickHouse在Server啟動時。main函數之中會調用registerAggregateFunction的初始化函數註冊所有的聚合函數。
然後調用到下面的函數:

void registerAggregateFunctionSum(AggregateFunctionFactory & factory)
{
    factory.registerFunction("sum", createAggregateFunctionSum<AggregateFunctionSumSimple>, AggregateFunctionFactory::CaseInsensitive);
    factory.registerFunction("sumWithOverflow", createAggregateFunctionSum<AggregateFunctionSumWithOverflow>);
    factory.registerFunction("sumKahan", createAggregateFunctionSum<AggregateFunctionSumKahan>);
}

這裏又調用了 factory.registerFunction("sum", createAggregateFunctionSum<AggregateFunctionSumSimple>, AggregateFunctionFactory::CaseInsensitive);來進行上述我們看到的聚合函數的註冊。這裡有一點很噁心的模板代碼,筆者這裏簡化了一下,把註冊的部分函數拉出來:

createAggregateFunctionSum(const std::string & name, const DataTypes & argument_types, const Array & parameters)
{
    AggregateFunctionPtr res;
    DataTypePtr data_type = argument_types[0];
    if (isDecimal(data_type))
        res.reset(createWithDecimalType<Function>(*data_type, *data_type, argument_types));
    else
        res.reset(createWithNumericType<Function>(*data_type, argument_types));
    return res;

這裏的Function模板就是上面的AggregateFunctionSumSimple, 而它又是下面的模板類型:

template <typename T> using AggregateFunctionSumSimple = typename SumSimple<T>::Function;

template <typename T>
struct SumSimple
{
    /// @note It uses slow Decimal128 (cause we need such a variant). sumWithOverflow is faster for Decimal32/64
    using ResultType = std::conditional_t<IsDecimalNumber<T>, Decimal128, NearestFieldType<T>>;
    using AggregateDataType = AggregateFunctionSumData<ResultType>;
    using Function = AggregateFunctionSum<T, ResultType, AggregateDataType>;
};

不知道讀者被繞暈了沒,最終繞回來還是new出來這個AggregateFunctionSum<T, ResultType, AggregateDataType>
也就是完成了這個求和算子的註冊,後續我們get出來就可以愉快的調用啦。(這裏這部分的模板變化比較複雜,如果看不明白可以回到源碼梳理一下~~~)

3. 小結

好了,關於聚合函數的基礎信息,和它是如何實現並且通過工廠方法註冊獲取的流程算是搞明白了。
關於其他的聚合算子,也是大同小異的方式。筆者就不再贅述了,感興趣的可以回到源碼之中繼續一探究竟。講完了聚合函數的實現,下一篇筆者就要繼續給探究聚合函數究竟在ClickHouse之中是如何和列存結合使用,並實現向量化的~~。
筆者是一個ClickHouse的初學者,對ClickHouse有興趣的同學,也歡迎和筆者多多指教,交流。

4. 參考資料

官方文檔
ClickHouse源代碼

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

如何在Spring Boot應用啟動之後立刻執行一段邏輯_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

1. 前言

不知道你有沒有接到這種需求,項目啟動后立馬執行一些邏輯。比如簡單的緩存預熱,或者上線后的廣播之類等等。如果你使用 Spring Boot 框架的話就可以藉助其提供的接口CommandLineRunnerApplicationRunner來實現。

2. CommandLineRunner

org.springframework.boot.CommandLineRunnerSpring Boot提供的一個接口,當你實現該接口並將之注入Spring IoC容器后,Spring Boot應用啟動后就會執行其run方法。一個Spring Boot可以存在多個CommandLineRunner的實現,當存在多個時,你可以實現Ordered接口控制這些實現的執行順序(Order 數值越大優先級越低)。接下來我們來聲明兩個實現並指定順序:

優先執行:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 優先級最高
 * 該類期望在springboot 啟動后第一順位執行
 * @author felord.cn
 * @since 12:57
 **/
@Slf4j
@Component
public class HighOrderCommandLineRunner implements CommandLineRunner, Ordered {
    @Override
    public void run(String... args) throws Exception {
        for (String arg : args) {
            log.info("arg = " + arg);
        }
        log.info("i am highOrderRunner");
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}

第二順序執行:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

/**
 * 優先級低於{@code HighOrderCommandLineRunner}
 * @author felord.cn
 * @since 12:59
 **/
@Slf4j
@Component
public class LowOrderCommandLineRunner implements CommandLineRunner, Ordered {

    @Override
    public void run(String... args) throws Exception {
        log.info("i am lowOrderRunner");
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+1;
    }
}

然後啟動Spring Boot應用后,控制台按照預定的順序打印出了結果:

2020-05-30 23:11:03.685  INFO 11976 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2020-05-30 23:11:03.701  INFO 11976 --- [           main] c.f.Application  : Started SpringBootApplication in 4.272 seconds (JVM running for 6.316)
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-05-30 23:11:03.706  INFO 11976 --- [           main] c.f.LowOrderCommandLineRunner   : i am lowOrderRunner

3. ApplicationRunner

Spring Boot 1.3.0又引入了一個和CommandLineRunner功能一樣的接口ApplicationRunnerCommandLineRunner接收可變參數String... args,而ApplicationRunner 接收一個封裝好的對象參數ApplicationArguments。除此之外它們功能完全一樣,甚至連方法名都一樣。 聲明一個ApplicationRunner並讓它優先級最低:

package cn.felord;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 優先級最低
 * @author felord.cn
 * @since 13:00
 **/
@Slf4j
@Component
public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("i am applicationRunner");
        Set<String> optionNames = args.getOptionNames();
        log.info("optionNames = " + optionNames);
        String[] sourceArgs = args.getSourceArgs();
        log.info("sourceArgs = " + Arrays.toString(sourceArgs));
        List<String> nonOptionArgs = args.getNonOptionArgs();
        log.info("nonOptionArgs = " + nonOptionArgs);
        List<String> optionValues = args.getOptionValues("foo");
        log.info("optionValues = " + optionValues);
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE+2;
    }
}

按照順序打印了三個類的執行結果:

2020-06-01 13:02:39.420  INFO 19032 --- [           main] c.f.MybatisResultmapApplication  : Started MybatisResultmapApplication in 1.801 seconds (JVM running for 2.266)
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionNames = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = []
2020-06-01 13:02:39.423  INFO 19032 --- [           main] c.f.DefaultApplicationRunner     : optionValues = null

Ordered接口並不能被 @Order註解所代替。

4. 傳遞參數

相信很多同學看到這裏都開始對這兩個run方法的入參感興趣了。Spring Boot應用啟動時是可以接受參數的,換句話說也就是Spring Bootmain方法是可以接受參數的。這些參數通過命令行 java -jar yourapp.jar 來傳遞。CommandLineRunner會原封不動照單全收這些接口,這些參數也可以封裝到ApplicationArguments對象中供ApplicationRunner調用。 我們來認識一下ApplicationArguments的相關方法:

  • getSourceArgs() 被傳遞給應用程序的原始參數,返回這些參數的字符串數組。

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

  • getOptionNames() 獲取選項名稱的Set字符串集合。如 --spring.profiles.active=dev --debug 將返回["spring.profiles.active","debug"]

  • getOptionValues(String name) 通過名稱來獲取該名稱對應的選項值。如--foo=bar --foo=baz 將返回["bar","baz"]

  • containsOption(String name) 用來判斷是否包含某個選項的名稱。

  • getNonOptionArgs() 用來獲取所有的無選項參數。

    接下來我們試驗一波,你可以通過下面的命令運行一個 Spring Boot應用 Jar

java -jar yourapp.jar --foo=bar --foo=baz --dev.name=碼農小胖哥 java felordcn

或者在IDEA開發工具中打開Spring Boot應用main方法的配置項,進行如下配置,其他IDE工具同理。

運行Spring Boot應用,將會打印出:

2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=bar
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --foo=baz
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = --dev.name=碼農小胖哥
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = java
2020-06-01 15:04:31.490  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : arg = felordcn
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.HighOrderCommandLineRunner   : i am highOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.LowOrderCommandLineRunner    : i am lowOrderRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : i am applicationRunner
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionNames = [dev.name, foo]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : sourceArgs = [--foo=bar, --foo=baz, --dev.name=碼農小胖哥, java, felordcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : nonOptionArgs = [java, felordcn]
2020-06-01 15:04:31.491  INFO 13208 --- [           main] c.f.DefaultApplicationRunner     : optionValues = [bar, baz]

然後你就可以根據實際需要動態地執行一些邏輯。

5. 總結

今天我們對CommandLineRunnerApplicationRunner進行了講解,從用法到順序執行,又對Spring Boot傳遞參數進行了介紹和演示,希望對你有所幫助。多多關注:碼農小胖哥,更多編程乾貨分享給你。

關注公眾號:Felordcn 獲取更多資訊

個人博客:https://felord.cn

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

深入了解ConcurrentHashMap_網頁設計公司

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

在上一篇文章【簡單了解系列】從基礎的使用來深挖HashMap里,我從最基礎的使用中介紹了HashMap,大致是JDK1.7和1.8中底層實現的變化,和介紹了為什麼在多線程下可能會造成死循環,擴容機制是什麼樣的。感興趣的可以先看看。

我們知道,HashMap是非線程安全的容器,那麼為什麼ConcurrentHashMap能夠做到線程安全呢?

底層結構

首先看一下ConcurrentHashMap的底層數據結構,在Java8中,其底層的實現方式與HashMap一樣的,同樣是數組、鏈表再加紅黑樹,具體的可以參考上面的HashMap的文章,下面所有的討論都是基於Java 1.8。

transient volatile Node<K,V>[] table;

volatile關鍵字

對比HashMap的底層結構可以發現,table的定義中多了一個volatile關鍵字。這個關鍵字是做什麼的呢?我們知道所有的共享變量都存在主內存中,就像table。

而線程對變量的所有操作都必須在線程自己的工作內存中完成,而不能直接讀取主存中的變量,這是JMM的規定。所以每個線程都會有自己的工作內存,工作內存中存放了共享變量的副本。而正是因為這樣,才造成了可見性的問題。

ABCD四個線程同時在操作一個共享變量X,此時如果A從主存中讀取了X,改變了值,並且寫回了內存。那麼BCD線程所得到的X副本就已經失效了。此時如果沒有被volatile修飾,那麼BCD線程是不知道自己的變量副本已經失效了。繼續使用這個變量就會造成數據不一致的問題。

內存可見性

而如果加上了volatile關鍵字,BCD線程就會立馬看到最新的值,這就是內存可見性。你可能想問,憑什麼加了volatile的關鍵字就可以保證共享變量的內存可見性?

那是因為如果變量被volatile修飾,在線程進行寫操作時,會直接將新的值寫入到主存中,而不是線程的工作內存中;而在讀操作時,會直接從主存中讀取,而不是線程的工作內存。

基礎使用

首先這個使用與HashMap沒有任何區別,只是實現改成了ConcurrentHashMap。

Map<String, String> map = new ConcurrentHashMap<>();
map.put("微信搜索", "SH的全棧筆記");
map.get("微信搜索"); // SH的全棧筆記

取值

首先我們來看一下get方法的使用,源碼如下。

public V get(Object key) {
  Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
  int h = spread(key.hashCode());
  if ((tab = table) != null && (n = tab.length) > 0 &&
      (e = tabAt(tab, (n - 1) & h)) != null) {
    if ((eh = e.hash) == h) {
      if ((ek = e.key) == key || (ek != null && key.equals(ek)))
        return e.val;
    }
    else if (eh < 0)
      return (p = e.find(h, key)) != null ? p.val : null;
    while ((e = e.next) != null) {
      if (e.hash == h &&
          ((ek = e.key) == key || (ek != null && key.equals(ek))))
        return e.val;
    }
  }
  return null;
}

大概解釋一下這個過程發生了什麼,首先根據key計算出哈希值,如果找到了就直接返回值。如果是紅黑樹的話,就在紅黑樹中查找值,否則就按照鏈表的查找方式查找。

這與HashMap也差不多的,元素會首先以鏈表的方式進行存儲,如果該桶中的元素數量大於TREEIFY_THRESHOLD的值,就會觸發樹化。將當前的鏈錶轉換為紅黑樹。因為如果數量太多的話,鏈表的查詢效率就會變得非常低,時間複雜度為O(n),而紅黑樹的查詢時間複雜度則為O(logn),這個閾值在Java 1.8中的默認值為8,定義如下。

static final int TREEIFY_THRESHOLD = 8;

賦值

put的源碼就不放出來了,放在這大家估計也不會一行一行的去看。所以我就簡單的解釋一下put的過程發生了什麼事,並貼上關鍵代碼就好了。

整個過程,除開併發的一些細節,大致的流程和1.8中的HashMap是差不多的。

  • 首先會根據傳入的key計算出hashcode,如果是第一次被賦值,那自然需要進行初始化table
  • 如果這個key沒有存在過,直接用CAS在當前槽位的頭節點創建一個Node,會用自旋來保證成功
  • 如果當前的Node的hashcode是否等於-1,如果是則證明有其它的線程正在執行擴容操作,當前線程就加入到擴容的操作中去
  • 且如果該槽位(也就是桶)上的數據結構如果是鏈表,則按照鏈表的插入方式,直接接在當前的鏈表的後面。如果數量大於了樹化的閾值就會轉為紅黑樹。
  • 如果這個key存在,就會直接覆蓋。
  • 判斷是否需要擴容

看到這你可能會有一堆的疑問。

例如在多線程的情況下,幾個線程同時來執行put操作時,怎麼保證只執行一次初始化,或者怎麼保證只執行一次擴容呢?萬一我已經寫入了數據,另一個線程又初始化了一遍,豈不是造成了數據不一致的問題。同樣是多線程的情況下, 怎麼保證put值的時候不會被其他線程覆蓋。CAS又是什麼?

接下來我們就來看一下在多線程的情況下,ConcurrentHashMap是如何保證線程安全的。

初始化的線程安全

首先我們來看初始化的源碼。

private final Node<K,V>[] initTable() {
  Node<K,V>[] tab; int sc;
  while ((tab = table) == null || tab.length == 0) {
    if ((sc = sizeCtl) < 0)
      Thread.yield(); // lost initialization race; just spin
    else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
      try {
        if ((tab = table) == null || tab.length == 0) {
          int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
          @SuppressWarnings("unchecked")
          Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
          table = tab = nt;
          sc = n - (n >>> 2);
        }
      } finally {
        sizeCtl = sc;
      }
      break;
    }
  }
  return tab;
}

可以看到有一個關鍵的變量,sizeCtl,其定義如下。

private transient volatile int sizeCtl;

sizeCtl使用了關鍵字volatile修飾,說明這是一個多線程的共享變量,可以看到如果是首次初始化,第一個判斷條件if ((sc = sizeCtl) < 0)是不會滿足的,正常初始化的話sizeCtl的值為0,初始化設定了size的話sizeCtl的值會等於傳入的size,而這兩個值始終是大於0的。

CAS

然後就會進入下面的U.compareAndSwapInt(this, SIZECTL, sc, -1)方法,這就是上面提到的CAS,Compare and Swap(Set),比較並交換,Unsafe是位於sun.misc下的一個類,在Java底層用的比較多,它讓Java擁有了類似C語言一樣直接操作內存空間的能力。

例如可以操作內存、CAS、內存屏障、線程調度等等,但是如果Unsafe類不能被正確使用,就會使程序變的不安全,所以不建議程序直接使用它。

compareAndSwapInt的四個參數分別是,實例、偏移地址、預期值、新值。偏移地址可以快速幫我們在實例中定位到我們要修改的字段,此例中便是sizeCtl。如果內存當中的sizeCtl是傳入的預期值,則將其更新為新的值。這個Unsafe類的方法可以保證這個操作的原子性。當你在使用parallelStream進行併發的foreach遍歷時,如果涉及到修改一個整型的共享變量時,你肯定不能直接用i++,因為在多線程下,i++每次操作不能保證原子性。所以你可能會用到如下的方式。

AtomicInteger num = new AtomicInteger();
arr.parallelStream().forEach(item -> num.getAndIncrement());

你可能會好奇,為什麼使用了AtomicInteger就可以保證原子性,跟Unsafe類和CAS又有什麼關係,讓我們接着往下,看getAndIncrement方法的底層實現。

public final int getAndIncrement() {
  return unsafe.getAndAddInt(this, valueOffset, 1);
}

可以看到,底層調用的是Unsafe類的方法,這不就聯繫上了嗎,而getAndIncrement的實現又長這樣。

public final int getAndAddInt(Object var1, long var2, int var4) {
  int var5;
  do {
    var5 = this.getIntVolatile(var1, var2);
  } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
  return var5;
}

沒錯,這裏底層調用了compareAndSwapInt方法。可以看到這裏加了while,如果該方法返回false就一直循環,直到成功為止。這個過程有個的名字,叫自旋。特別高端啊,說人話就是無限循環。

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

什麼情況會返回false呢?那就是var5變量存儲的值,和現在內存中實際var5的值不同,說明這個變量已經被其他線程修改過了,此時通過自旋來重新獲取,直到成功為止,然後自旋結束。

結論

聊的稍微有點多,這小節的問題是如何保證不重複初始化。那就是執行首次擴容時,會將變量sizeCtl設置為-1,因為其被volatile修飾,所以其值的修改對其他線程可見。

其它線程再調用初始化時,就會發現sizeCtl的值為-1,說明已經有線程正在執行初始化的操作了,就會執行Thread.yield(),然後退出。

yield相信大家都不陌生,和sleep不同,sleep可以讓線程進入阻塞狀態,且可以指定阻塞的時間,同時釋放CPU資源。而yield不會讓線程進入阻塞狀態,而且也不能指定時間,它讓線程重新進入可執行狀態,讓出CPU調度,讓CPU資源被同優先級或者高優先級的線程使用,稍後再進行嘗試,這個時間依賴於當前CPU的時間片劃分。

如何保證值不被覆蓋

我們在上一節舉了在併發下i++的例子,說在併發下i++並不是一個具有原子性的操作,假設此時i=1,線程A和線程B同時取了i的值,同時+1,然後此時又同時的寫回。那麼此時i++的值會是2而不是3,在併發下1+1+1=2是可能出現的。

讓我們來看一下ConcurrentHashMap在目標key已經存在時的賦值操作,因為如果不存在會直接調用Unsafe的方法創建一個Node,所以後續的線程就會進入到下面的邏輯中來,由於太長,我省略了一些代碼。

......
V oldVal = null;
synchronized (f) {
  if (tabAt(tab, i) == f) {
    if (fh >= 0) {
      binCount = 1;
      for (Node<K,V> e = f;; ++binCount) {
        ......
      }
    }
    else if (f instanceof TreeBin) {
      Node<K,V> p;
      binCount = 2;
      if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) {
        oldVal = p.val;
        if (!onlyIfAbsent)
          p.val = value;
      }
    }
  }
}
if (binCount != 0) {
  if (binCount >= TREEIFY_THRESHOLD)
    treeifyBin(tab, i);
  if (oldVal != null)
    return oldVal;
  break;
}

上述代碼在賦值的邏輯外層包了一個synchronized,這個有什麼用呢?

synchronized關鍵字

這個地方也可以換一個方式來理解,那就是synchronized如何保證線程安全的。線程安全,我認為更多的是描述一種風險。在堆內存中的數據由於可以被任何線程訪問到,在沒有任何限制的情況下存在被意外修改的風險。

synchronized是通過對共享資源加鎖的方式,使同一時間只能有一個線程能夠訪問到臨界區(也就是共享資源),共享資源包括了方法、鎖代碼塊和對象。

那是不是使用了synchronized就一定能保證線程安全呢?不是的,如果不能正確的使用,很可能就會引發死鎖,所以,保證線程安全的前提是正確的使用synchronized

自動擴容的線程安全

除了初始化、併發的寫入值,還有一個問題值得關注,那就是在多線程下,ConcurrentHashMap是如何保證自動擴容是線程安全的。

擴容的關鍵方案是transfer,但是由於代碼太多了,貼在這個地方可能會影響大家的理解,感興趣的可以自己的看一下。

還是大概說一下自動擴容的過程,我們以一個線程來舉例子。在putVal的最後一步,會調用addCount方法,然後在方法里判讀是否需要擴容,如果容量超過了實際容量 * 負載因子(也就是sizeCtl的值)就會調用transfer方法。

計算分區的範圍

因為ConcurrentHashMap是支持多線程同時擴容的,所以為了避免每個線程處理的數量不均勻,也為了提高效率,其對當前的所有桶按數量(也就是上面提到的槽位)進行分區,每個線程只處理自己分到的區域內的桶的數據即可。

當前線程計算當前stride的代碼如下。

stride = (NCPU > 1) ? (n >>> 3) / NCPU : n);

如果計算出來的值小於設定的最小範圍,也就是private static final int MIN_TRANSFER_STRIDE = 16;,就把當前分區範圍設置為16。

初始化nextTable

nextTable也是一個共享變量,定義如下,用於存放在正在擴容之後的ConcurrentHashMap的數據,當且僅當正在擴容時才不為空。

private transient volatile Node<K,V>[] nextTable;

如果當前transfer方法傳入的nextTab(這是個局部變量,比上面提到的nextTable少了幾個字母,不要搞混了)是null,說明是當前線程是第一個調用擴容操作的線程,就需要初始化一個size為原來容量2被的nextTable,核心代碼如下。

Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1]; // 可以看到傳入的初始化容量是n << 1。

初始化成功之後就更新共享變量nextTable的值,並設置transferIndex的值為擴容前的length,這也是一個共享的變量,表示擴容使還未處理的桶的下標。

設置分區邊界

一個新的線程加入擴容操作,在完成上述步驟后,就會開始從現在正在擴容的Map中找到自己的分區。例如,如果是第一個線程,那麼其取到的分區就會如下。

start = nextIndex - 1;
end = nextIndex > stride ? nextIndex - stride : 0;
// 實際上就是當還有足夠的桶可以分的時候,線程分到的分區為 [n-stride, n - 1]

可以看到,分區是從尾到首進行的。而如果是首次進入的線程,nextIndex 的值會被初始化為共享變量transferIndex 的值。

Copy分區內的值

當前線程在自己劃分到的分區內開始遍歷,如果當前桶是null,那麼就生成一個 ForwardingNode,代碼如下。

ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);

並把當前槽位賦值為fwd,你可以把ForwardingNode理解為一個標誌位,如果有線程遍歷到了這個桶, 發現已經是ForwardingNode了,就代表這個桶已經被處理過了,就會跳過這個桶。

如果這個桶沒有被處理過,就會開始給當前的桶加鎖,我們知道ConcurrentHashMap會在多線程的場景下使用,所以當有線程正在擴容的時候,可能還會有線程正在執行put操作,所以如果當前Map正在執行擴容操作,如果此時再寫入數據,很可能會造成的數據丟失,所以要對桶進行加鎖。

總結

對比在1.7中採用的Segment分段鎖的臃腫設計,1.8中直接使用了CASSynchronized來保證併發下的線程安全。總的來說,在1.8中,ConcurrentHashMap和HashMap的底層實現都差不多,都是數組、鏈表和紅黑樹的方式。其主要區別就在於應用場景,非併發的情況可以使用HashMap,而如果要處理併發的情況,就需要使用ConcurrentHashMap。關於ConcurrentHashMap就先聊到這裏。

本文使用 mdnice 排版

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

怎麼才能識破賣車銷售詭計 底價提車回家?_網頁設計公司

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

對於一些包牌價比我們自己完成一系列上牌過程的便宜,是因為它們在購車發票上進行“少開”,購置稅是按發票價進行收取,它們只要少開數額就可以少交購置稅以及保險,中間的差價就是它們的盈利額。但是對於我們消費者來說若是車輛發生重大事故、泡水、自燃或者盜搶,保險公司是按發票價為基準進行賠償,這無疑增加了一部分風險。

前言

買車的過程,其實就是一個和銷售鬥智斗勇的過程,稍有不留心就很有可能讓你沒了幾千元,或者是買到一些沒用的東西,而且整個購車過程都是那麼複雜,我們應該如何應對呢?還有我們在購車的時候怎樣才能最低價買到自己心儀的汽車呢?

盡量選擇全款購車而不是貸款購車

全款購車的時候雙方就相當交換貨物而已,手續可以達到最簡化,僅僅需要拿到車輛合格證、發票就可以完成這次交易。但是貸款購車的話4S店多半強制讓你在店裡購買車險以及上牌,而且對於原本僅僅是500元左右的上牌費用,在他們手上就成了2000以上的費用了,並且也有個人資料泄露的危險。保險方面也要比起自行購買要高400-1000元。所以說全款購車是比較省心省錢的。

選擇提裸車而不是落地價

很多4S美而言之“一條龍服務”,會為用戶提供上牌、保險等一系列服務,但是正正和上一理由一樣,這樣會給你增加額外的費用。對於一些包牌價比我們自己完成一系列上牌過程的便宜,是因為它們在購車發票上進行“少開”,購置稅是按發票價進行收取,它們只要少開數額就可以少交購置稅以及保險,

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

中間的差價就是它們的盈利額。但是對於我們消費者來說若是車輛發生重大事故、泡水、自燃或者盜搶,保險公司是按發票價為基準進行賠償,這無疑增加了一部分風險。

不選購精品

在購車以後,銷售基本會“乘勝追擊”向你推薦各種精品,例如汽車貼膜、迎賓踏板、發動機下護板等,而且這些產品的價格基本都是外面的一倍有餘,會美而言之“原裝件”,但實際上汽車廠商並沒有做到這類型的精品,我們在某寶上只要搜索“原裝件”就能找到很多打着“原廠”符號的精品,並且會發現這些產品都是一些小作坊的產品。

對比各類型的金融產品

對於選擇貸款購車的人來說,利息以及手續費都是一筆不小的開支,而事實上每一個金融機構的利息以及手續費都是不一樣的,所以我們要合理對比,有些金融機構甚至是有着廠家貼息的,這樣無疑能給你省下上萬元,這種貼息的品牌多半以上汽、日產為主,具體還是要多方面比較、詢問,選擇合適的金融產品。

明確購車所需費用

對於一些無良的4S店,他們總是給你設置各種各樣的雜費,貸款手續費、出庫費層出不窮。所以我們在買車的時候一定要白紙黑字明確各方面的費用,對於所贈送的東西也要將其記錄下來並雙方簽字,這樣就不會出現突然收取不該有的費用或者是該有的優惠、贈品沒有落實的情況。

所以買車過程講究的就是不怕麻煩、細心、謹慎以及理性,這樣才能以最低價格買到自己心儀的汽車,而對於不熟悉流程或者是汽車的新手朋友最好還是尋求一位“老司機”一同購車。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。