月銷30000多輛,百公里6L油,這款10萬級家轎有這麼好?

在油耗方面,日產軒逸提供了1。6L以及1。8L兩款動力總成供消費者選擇,與之匹配的是一台CVT變速箱。而作為主銷車型的1。6L版本整體的動力表現並不會太過出色,但好在動力輸出平順,而且油耗水平做得相當出色,也是各大滴滴車主當中最火爆的車型之一。

在10多萬的這個價位區間中,無論是合資品牌還是國產品牌都有着數十款車型供你選擇,而對於絕大多數消費者而言,都是希望能買到一台價格便宜、用得放心的車型,於是你會發現不少人都變得十分苦惱,究竟自己看上的車型到底值不值得購買呢?成為了當前最希望解決的一個難題。

帶着問題,今天咱們先來討論一下日系三強當中熱度相當高的日產軒逸,究竟這一款車型的表現怎麼樣呢?

在造型方面相信大家對其也是相當熟悉,也是採用當下最常規的日產家族式設計語言,造型設計較為年輕,符合到當下消費者的審美,而且每月均保持數萬台的銷量(3月份37672輛)也足以證明它受到眾多消費者所熱捧。

有着沙發廠之稱的日產品牌,在軒逸上也做得相當出色,2700mm的軸距表現也賦予了它大空間舒適家用的亮點,而且車型本身也沒有明顯的短板,也是一款能夠滿足到各種家庭需求的車型。

雖然很多人都認為合資車型總會出現價格高配置低的情況,而實際上隨着車型的更新換代,你會發現其實原本配置簡陋的合資車型已經變得更具競爭力;

在配置水平方面日產軒逸雖說沒有過於突出的地方,在低配版本上配置可以說是相當低,所以也是不值得推薦的。但在主銷的中高配版本,豐富的配置水平也讓其性價比極高;而且在高配版本上頁新增加了併線輔助、車道偏離系統、主動剎車等科技含量比較高的配置,也是這個價位當中極其少有的存在。

在油耗方面,日產軒逸提供了1.6L以及1.8L兩款動力總成供消費者選擇,與之匹配的是一台CVT變速箱。而作為主銷車型的1.6L版本整體的動力表現並不會太過出色,但好在動力輸出平順,而且油耗水平做得相當出色,也是各大滴滴車主當中最火爆的車型之一。

而在保養方面,日系車最大的優勢便是保養費用不高,而且車型的耐久性相當高,開着不壞、用起來相當省心。

優點:車型造型大氣、油耗出色、儲物和乘坐空間大,很適合家用

缺點:沒有後排出風口、沒有標配倒車雷達、動力和操控較弱

就像上文所說,軒逸更推薦考慮車價為13.78萬的1.6L尊享版或以上的車型版本,而車型本身的價格並不算太高,但是軒逸也是擁有着一個相當不錯的現金優惠,也幾乎可以用原車價去購車。

關於軒逸而言,其實多年在市場上打滾也讓它在消費者心目當中有着非常不錯的口碑,舒適家用也是它的優勢之處,而車型本身並沒有明顯的短板,雖然表現平平但不失為一台及格的家用轎車。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

同級最便宜,這款20多萬的超帥氣SUV車主卻說……

0L混動最大馬力(pS):182/發動機:146 電動機:184最大扭矩(Nm):240/發動機:175 電動機:315變速箱:8DCT/E-CVT百公里加速(s):8。35/8。6百公里油耗(L):6。8/5車主百公里油耗(L):8。71/暫

謳歌CDX肩負着在國內為謳歌品牌打開市場的重任,它具備極其前衛的設計風格,而且看到實車時你就會感受到其設計的精緻感!

寬敞的空間,前衛設計讓它具有不錯的競爭力。而且它搭載一款1.5T高功率發動機,匹配一副8擋雙離合變速箱,動力系統匹配是高效的,它換擋平順,降擋的速度也相當快,動力表現可圈可點!下面我們就來看看這款豪華SUV車型的各方面表現怎麼樣吧!

長寬高:4496*1840*1615mm

軸距:2660mm

定位:緊湊型SUV

設計激進的謳歌CDX可謂是同級車型中的一股清流,前臉造型極其激進,鑽石形中網造型顯得相當有個性。同時車身線條緊湊,但車內卻能營造出足夠的乘坐空間。

內飾方面它在細節處富有創意,造型類似“如意”的旋鈕擋把設計科技感強,而內飾的用料也是到位的。值得一提的是這套內飾的按鍵布局簡約、合理,方向盤上的按鍵也具備不錯手感,在行車過程中操作便利!

發動機:1.5T/2.0L混動

最大馬力(pS):182/發動機:146 電動機:184

最大扭矩(Nm):240/發動機:175 電動機:315

變速箱:8DCT/E-CVT

百公里加速(s):8.35/8.6

百公里油耗(L):6.8/5

車主百公里油耗(L):8.71/暫本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

都是30萬德系轎車,頂配邁騰和奧迪A4L到底差多少?

其實邁騰多出來的配置不止這些,還有二十多項,全部寫出來太長,故略去。低配的奧迪A4L採用了低功率的2。0T發動機,最大馬力是190匹,最大扭矩是320牛•米。頂配的邁騰使用的2。0T發動機賬面數據更好,220匹的最大馬力和350牛•米的最大扭矩均優於A4L。

隨着平台化,規模化生產的普及,很多大集團都會在自己的普通品牌和豪華品牌上通用零件,但是定價卻差了幾萬,那麼這幾萬的差價真的如大家所說,是LOGO的差異嗎?同一個集團,應該買TA的普通品牌高配車型還是豪華品牌的低配車型比較划算?

今天,我們來對比一下大眾邁騰的380TSI 旗艦版和奧迪A4L的40TFSI 進取版,看看哪個更值得買。

邁騰和奧迪A4L的外觀是同一個風格的兩份答卷。邁騰的橫貫式前臉把大燈連接起來,從視覺上來看顯得更寬更低矮。今天對比的邁騰380TSI 旗艦版配備的是18寸輪轂,所以邁騰的側面看上去更加大氣一些。

奧迪A4L則是在原有的六邊形格柵的家族設計元素上再下功夫,把大燈、格柵、車身線條設計得再銳利一些,所以奧迪A4L的外觀顯得更加年輕。不過這17寸的輪轂嘛,說實話不是很能襯托出A4L的檔次,建議後期更換。

這一局,邁騰略勝。

這一代的邁騰是歐版帕薩特直接拿來生產的,所以這一代邁騰的風格反而是繼承了上一代帕薩特的商務風。在邁騰上,木紋飾板貫穿整个中控台,空調出風口被設計得更高,所以空間更加寬闊。奧迪A4L的內飾以科技感為主要設計導向,奧迪A4L 30TSI 進取版採用中控台採用了銀色拉絲面板,中控屏採用懸浮式設計。可惜的是低配車沒有使用全液晶显示屏,空調面板也不是高配的那款金屬質感控制面板。所以質感稍顯不足。

這一局,也是邁騰勝出。

無論是邁騰還是奧迪A4L,引進國內后,都進行了不同程度的加長,邁騰的軸距為2871mm,比海外版增加了80mm,奧迪A4L的軸距是2908mm,比海外版增加了88mm。雖然奧迪A4L的軸距比邁騰要長一點,但是乘坐空間方面,邁騰比奧迪A4L要寬敞一點。這是因為邁騰是MQB(發動機橫置平台)的產物,而奧迪A4L是MLB(發動機縱置平台)的產物。發動機橫置的結構比較緊湊,占乘坐空間較少,所以邁騰的乘坐空間比奧迪A4L稍微大一點。

這一局,因為兩者的差距微乎其微,所以判定兩者打成平手。

在配置上,邁騰完勝沒什麼懸念。其實邁騰多出來的配置不止這些,還有二十多項,全部寫出來太長,故略去。

低配的奧迪A4L採用了低功率的2.0T發動機,最大馬力是190匹,最大扭矩是320牛•米。頂配的邁騰使用的2.0T發動機賬面數據更好,220匹的最大馬力和350牛•米的最大扭矩均優於A4L。從加速成績來看,邁騰比奧迪A4L更好,但也只是半秒的差距。奧迪A4L的發動機有AVS可變氣門升程技術和混合噴射技術。這兩項技術都可以提高燃油經濟性,所以從用戶反饋的數據來看,奧迪A4L比邁騰節油不少。

所以這局,也只能判五五開。

說到舒適性方面奧迪A4L的前後懸挂都使用了五連桿獨立懸挂,而邁騰則採用了前麥弗遜獨立懸挂后多連桿獨立懸挂的組合。這不僅是因為成本,還因為邁騰使用的MQB佔據了機艙空間,所以無法布局多連桿懸挂。麥弗遜式獨立懸挂有個缺點,那就是上下運動的時候對車輪外傾角變化明顯,而車輪外傾角變化會影響操縱的穩定性。所以,為了安全性考慮,麥弗遜懸挂一般都會比較硬。而使用五連桿的奧迪A4L可以把懸挂調得軟一些,所以奧迪A4L的濾震更好。在加上在隔音材料方面,豪華品牌比普通品牌的投入會更大。

所以舒適性方面,奧迪A4L完勝邁騰是沒什麼懸念的。

總結:縱觀兩車各個方面的對比,互有勝負。豪華品牌的車不是只掛着一個LOGO就賣這麼貴,如果你坐過邁騰后再坐A4L,你確確實實能夠感受到豪華車帶給你的那種舒適感,高級感。但是在靜態體驗的時候,邁騰的頂配版可以說是完虐奧迪A4L了。所以,我建議,如果你打算購買一台商務車,邁騰的頂配版更加合適。如果只是買來自用,奧迪A4L值得考慮。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?

花25.88萬買漢蘭達的人看見榮威RX8會相當後悔?

通過尺寸對比表,我們可以看出榮威RX8的三圍比漢蘭達要更大一些,軸距也比漢蘭達長60mm,營造出充足的7座空間。而且榮威RX8的第三排的膝部/頭部空間比漢蘭達大一拳,全幅靠背的採用舒適性更好。230mm同級稱冠的第二排座椅可調行程以及特有的Easy–Entry一鍵放倒功能,進出第三排的便利性更高。

談起7座的SUV,大家都會聯想到充沛的乘坐空間、良好的通過性等標籤,它們擁有着極高的實用性,在生活方式日益多樣化的今天已成為汽車消費升級的首選,漢蘭達可以說是其中最熱門的車型之一,但是7座SUV車型之間的競爭越來越激烈,全新打造的車型越來越多,漢蘭達不得不面臨一位強勁對手發起的挑戰!

它就是來自上汽榮威的“全領域大7座豪華SUV”車型榮威RX8!它是一款基於上汽新一代IS(智能化SUV)平台打造,具備“ALL-DRIVE”智能全領域駕駛系統,也擁有寬敞7座空間的重點車型!而這兩款車型在價格上有所重疊,到底榮威RX8能不能戰勝目前7座SUV界最火車型呢?虎哥就來和大家一探究竟!

不得不和大家先嘮嗑一下車型的價格,因為榮威RX8已經在北京車展正式上市,虎哥認為其售價富有誠意,吸引力絕對不低,給予消費者選擇的空間也更多。

咱們選取售價為22.88萬的榮威RX8 2018款 30T 智聯網四驅至尊版車型和指導價為25.88萬的豐田漢蘭達2.0T四驅精英版進行直接對比。

先來對比外觀造型,榮威RX8的前臉採用了“律動”設計語言,造型富有力量感。全LED騰雲大燈科技感強,視覺也相當舒展,4顆透鏡式LED燈源組成的獵戶座星雲霧燈,也顯得炯炯有神。

(注:拍攝視頻車型為2017款漢蘭達)

榮威RX8的車身還具備黃金分割設計短前懸長后懸的豪華四驅車身比例,看上去具備動感,側面也刻畫出強而有力的輪包曲面。尾部設計橫向舒展,它具備內切燕尾、梯形的尾門的設計特點,比較有意思的是定音錘尾燈造型帶有“一錘定音”的寓意,細節處理值得仔細欣賞!

新款漢蘭達的外觀設計在原有基礎上有所升級,它進氣格柵的面積得到擴大,但是車身輪廓仍舊屬於中庸的設計風格。

視覺上略顯沉悶,而大燈造型的變化不大,它融入了LED日間行車燈,相比榮威RX8的全LED燈組顯得精緻感不足。車尾的造型敦實,造型飽滿但精緻感略顯不足。

榮威RX8品牌家族化設計相當舒展、座艙採用環繞式設計富有層次感、體現出精緻豪華也兼具優雅的設計風格。用料相當考究,大面積皮質軟包與淡雅木紋飾板帶來良好觸感,10.1英寸中控大屏也富有科技感,細節處理也進一步提升了精緻感!

而漢蘭達的內飾質感則顯得比較遜色,它中控布局簡潔明了,採用的軟質材料不少,看上去比較大氣。但是軟包面積不及榮威RX8,6.1英寸中控屏多媒體娛樂系統也顯得有些小氣。

在大家相當關心的配置方面,榮威RX8拉開了明顯的優勢!值得一提的是在用戶舒適性營造方面它十分到位,無線充電、真皮座椅、主駕駛電動調節、前排座椅加熱+通風、第二排座椅加熱、大面積採光的全景天窗、獨立式空氣凈化器它均有配備!

而且科技配備也已相當齊全,它配備有車機手機雙向WIFI、AI人工智能語音系統、主動導航系統、智能操作系統、虛擬儀錶、loT手機遠程車控系統等潮流前端的科技配備,配置方面的優勢十分明顯!

通過尺寸對比表,我們可以看出榮威RX8的三圍比漢蘭達要更大一些,軸距也比漢蘭達長60mm,營造出充足的7座空間。而且榮威RX8的第三排的膝部/頭部空間比漢蘭達大一拳,全幅靠背的採用舒適性更好!230mm同級稱冠的第二排座椅可調行程以及特有的Easy–Entry一鍵放倒功能,進出第三排的便利性更高。漢蘭達第二排僅有150mm的移動距離,便利性有待提高。

榮威RX8採用了BBA豪華品牌供應商德國Bader的頂級頭層小公牛皮座椅,而且還應用階梯式劇院座椅布局,每排乘客能享受舒適坐姿、視野開闊,並且NVH靜音水準較高,還配備大採光面積全景天窗。

舒適配置全面,榮威RX8的前排擁有電動調節、主駕迎賓記憶、遠程座椅加熱、三檔加熱和通風等功能,第二排乘客也能享受座椅加熱功能,這功能在冬天相當實用!而漢蘭達則採用織物座椅,缺乏座椅加熱、通風功能,前排座椅沒有沒有電動調節,實用性不及榮威RX8。

榮威RX8搭載縱置布局的“藍芯”2.0TGI缸內直噴渦輪增壓發動機,它具備全鋁缸體、雙可變氣門正時技術、渦輪增壓等高效科技,輸出224馬力最大功率、360牛米最大扭矩,動力輸出優於漢蘭達。

與之匹配的是一款縱置愛信6速手自一體變速箱,動力輸出具備平順性、高效率的特點,這讓榮威RX8具備9.1秒的百公里加速和9.1L/100km綜合油耗的出眾表現!

此外榮威RX8全系標配雙活塞浮動式制動卡鉗和陶瓷剎車片,這讓它的100-0km/h制動距離僅38米,要知道這是一款大尺寸的7座SUV車型,日常駕駛富有底氣!而某主流汽車媒體實測的漢蘭達剎車距離已超過41米,與榮威RX8有着不少差距。

咱們先來看看硬件配備,榮威RX8採用高強度非承載式車身、雙叉臂獨立前懸架+五連桿后懸架,車身剛性高、抗扭能力強。它還具備較大后傾角設定,比起採用承載式車身設計的漢蘭達更能適應各種道路情況!

而且榮威RX8公路駕駛時擁有良好的操控性、舒適性,它還搭載全時四驅系統和專業級中央、後橋差速鎖,可實現2驅和4驅鎖止!自動机械後橋限滑差速器在左右車輪速差超過120轉/分鐘時會自動鎖死,在複雜路面脫困能力高。

漢蘭達則屬於承載式車身的城市SUV,採用的是基於前橫置的適時四驅系統,而且它僅有中央差速器鎖止功能,通過性不強,更適合市區路段。

而且在四驅系統標定這一重要的軟實力方面,榮威RX8 無疑更加全面,下面咱們通過一個表格來詳細對比:

榮威RX8帶有六大地形駕駛模式,在各種路況上適應能力強不少,而且雪地、越野、低速這三個駕駛模式能針對複雜的越野路面,實用性比漢蘭達高不少。

榮威RX8搭載全新一代互聯網汽車智能系統-,即基於AliOS的斑馬智行解決方案,各項功能符合時下潮流,實用性強!在硬件上榮威RX8搭載10.1英寸高清中控屏和7英寸虛擬儀錶,显示清晰,操控更加便利,提升駕駛安全性。同時也提供了車機手機雙向WiFi和基礎服務、基本流量終身免費。

而在這一價位中的漢蘭達只有6.1英寸多媒體娛樂系統,導航、有手機映射、聯網功能欠奉,功能性上落後於時代。

寫在最後:經過全面的對比,咱們可以發現榮威RX8的外觀設計、內飾豪華度、科技感、配置豐富程度、乘坐空間、複雜路面適應性能、四驅系統全面性上都具備優勢,其實這也在意料之中,現在車型迭代迅速,作為全新車型的榮威RX8明顯具有後來居上之優勢,也極有潛力成為7座SUV中最有競爭力的車型!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

要成為合格的女司機,最大的挑戰是什麼?

可是,要完成這一次挑戰,我必須要有一台車。這次和我一起挑戰的,是全新昂科威28T頂配車型,2。0T發動機搭配9AT變速箱,擁有260匹馬力,還配備了CDC主動懸挂。2。0T發動機符合我對動力跟經濟性的需求。相比以前,全新的9AT變速箱也足夠聰明,足以應付多種路況。

大家好,我是小喬,說真的,我有點害怕。

作為一個女司機,我覺得我的駕駛技術算挺好了,但為什麼,我的知名程度,遠遠不如那個長得跟我差不多的Jacky呢?

到底是“7200干它”成就了他,還是他成就了“7200干它”,這個問題,在我腦海中迴旋,如同先有雞還是先有蛋的生物史拷問,令我疑惑不已。終於,我決定卧薪嘗膽,直接跟他當面對質爆紅的真諦!

Jacky面對我的質疑,嘴角微微上揚,說到:“既然你誠心誠意想要爆紅,那我就大發慈悲地成全你, 別克SUV強者挑戰之旅,這個對精神以及體力都有極大考驗的活動,就決定讓你參加了!“

挑戰內容

挑戰一:體能挑戰:限時挑戰3公里高空棧道。優秀的司機必須擁有強壯的體能!

挑戰二:耐力測試,獨自跑完4個小時高速全程,鍛煉作為司機的集中力和耐久力。

挑戰三:膽量挑戰:攀登懸崖天梯,鍛煉司機膽大心細的危急情況處理能力。

挑戰四:險中求勝:考驗司機越野路面的駕駛能力。

手拿這份挑戰清單,我感到一絲恐懼,但誓要成為女車神的我,不會輕易認輸!

可是,要完成這一次挑戰,我必須要有一台車。這次和我一起挑戰的,是全新昂科威28T頂配車型,2.0T發動機搭配9AT變速箱,擁有260匹馬力,還配備了CDC主動懸挂。

2.0T發動機符合我對動力跟經濟性的需求;相比以前,全新的9AT變速箱也足夠聰明,足以應付多種路況;它的懸架還能主動變化,公路、越野我都能舒舒服服。這一次挑戰,我勢在必得。

想知道到底Jacky給小喬的挑戰有多可怕?讓小喬這個沒心沒肺的女人都感到驚慌,而她又能否順利完成任務?趕緊點開視頻看一看!

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

※教你寫出一流的銷售文案?

※超省錢租車方案

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※產品缺大量曝光嗎?你需要的是一流包裝設計!

用python做時間序列預測九:ARIMA模型簡介

本篇介紹時間序列預測常用的ARIMA模型,通過了解本篇內容,將可以使用ARIMA預測一個時間序列。

什麼是ARIMA?

  • ARIMA是’Auto Regressive Integrated Moving Average’的簡稱。
  • ARIMA是一種基於時間序列歷史值和歷史值上的預測誤差來對當前做預測的模型。
  • ARIMA整合了自回歸項AR和滑動平均項MA。
  • ARIMA可以建模任何存在一定規律的非季節性時間序列。
  • 如果時間序列具有季節性,則需要使用SARIMA(Seasonal ARIMA)建模,後續會介紹。

ARIMA模型參數

ARIMA模型有三個超參數:p,d,q

  • p
    AR(自回歸)項的階數。需要事先設定好,表示y的當前值和前p個歷史值有關。
  • d
    使序列平穩的最小差分階數,一般是1階。非平穩序列可以通過差分來得到平穩序列,但是過度的差分,會導致時間序列失去自相關性,從而失去使用AR項的條件。
  • q
    MA(滑動平均)項的階數。需要事先設定好,表示y的當前值和前q個歷史值AR預測誤差有關。實際是用歷史值上的AR項預測誤差來建立一個類似歸回的模型。

ARIMA模型表示

  • AR項表示
    一個p階的自回歸模型可以表示如下:

    c是常數項,εt是隨機誤差項。
    對於一個AR(1)模型而言:
    當 ϕ1=0 時,yt 相當於白噪聲;
    當 ϕ1=1 並且 c=0 時,yt 相當於隨機遊走模型;
    當 ϕ1=1 並且 c≠0 時,yt 相當於帶漂移的隨機遊走模型;
    當 ϕ1<0 時,yt 傾向於在正負值之間上下浮動。

  • MA項表示
    一個q階的預測誤差回歸模型可以表示如下:

    c是常數項,εt是隨機誤差項。
    yt 可以看成是歷史預測誤差的加權移動平均值,q指定了歷史預測誤差的期數。

  • 完整表示

    即: 被預測變量Yt = 常數+Y的p階滯后的線性組合 + 預測誤差的q階滯后的線性組合

ARIMA模型定階

看圖定階

差分階數d
  • 如果時間序列本身就是平穩的,就不需要差分,所以此時d=0。
  • 如果時間序列不平穩,那麼主要是看時間序列的acf圖,如果acf表現為10階或以上的拖尾,那麼需要進一步的差分,如果acf表現為1階截尾,則可能是過度差分了,最好的差分階數是使acf先拖尾幾階,然後截尾。
  • 有的時候,可能在2個階數之間無法確定用哪個,因為acf的表現差不多,那麼就選擇標準差小的序列。
  • 下面是原時間序列、一階差分后、二階差分后的acf圖:

    可以看到,原序列的acf圖的拖尾階數過高了,而二階差分后的截尾階數過小了,所以一階差分更合適。

python代碼:

import numpy as np, pandas as pd
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
import matplotlib.pyplot as plt
plt.rcParams.update({'figure.figsize':(9,7), 'figure.dpi':120})

# Import data : Internet Usage per Minute
df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/wwwusage.csv', names=['value'], header=0)

# Original Series
fig, axes = plt.subplots(3, 2, sharex=True)
axes[0, 0].plot(df.value); axes[0, 0].set_title('Original Series')
plot_acf(df.value, ax=axes[0, 1])

# 1st Differencing
axes[1, 0].plot(df.value.diff()); axes[1, 0].set_title('1st Order Differencing')
plot_acf(df.value.diff().dropna(), ax=axes[1, 1])

# 2nd Differencing
axes[2, 0].plot(df.value.diff().diff()); axes[2, 0].set_title('2nd Order Differencing')
plot_acf(df.value.diff().diff().dropna(), ax=axes[2, 1])

plt.show()
AR階數p

AR的階數p可以通過pacf圖來設定,因為AR各項的係數就代表了各項自變量x對因變量y的偏自相關性。

可以看到,lag1,lag2之後,偏自相關落入了藍色背景區間內,表示不相關,所以這裏階數可以選擇2,或者保守點選擇1。

MA階數q

MA階數通過acf圖來設定,因為MA是預測誤差,預測誤差是自回歸預測和真實值之間的偏差。定階過程類似AR階數的設定過程。這裏可以選擇3,或者保守點選擇2。

信息準則定階

  • AIC(Akaike Information Criterion)

    L是數據的似然函數,k=1表示模型考慮常數c,k=0表示不考慮。最後一個1表示算上誤差項,所以其實第二項就是2乘以參數個數。

  • AICc(修正過的AIC)
  • BIC(Bayesian Information Criterion)

注意事項:

  • 信息準則越小,說明參數的選擇越好,一般使用AICc或者BIC。
  • 差分d,不要使用信息準則來判斷,因為差分會改變了似然函數使用的數據,使得信息準則的比較失去意義,所以通常用別的方法先選擇出合適的d。
  • 信息準則的好處是可以在用模型給出預測之前,就對模型的超參做一個量化評估,這對批量預測的場景尤其有用,因為批量預測往往需要在程序執行過程中自動定階。

構建ARIMA模型

from statsmodels.tsa.arima_model import ARIMA

# 1,1,2 ARIMA Model
model = ARIMA(df.value, order=(1,1,2))
model_fit = model.fit(disp=0)
print(model_fit.summary())

中間的表格列出了訓練得到的模型各項和對應的係數,如果係數很小,且‘P>|z|’ 列下的P-Value值遠大於0.05,則該項應該去掉,比如上圖中的ma部分的第二項,係數是-0.0010,P-Value值是0.998,那麼可以重建模型為ARIMA(1,1,1),從下圖可以看到,修改階數后的模型的AIC等信息準則都有所降低:

檢查殘差

通常會檢查模型擬合的殘差序列,即訓練數據原本的序列減去訓練數據上的擬合序列后的序列。該序列越符合隨機誤差分佈(均值為0的正態分佈),說明模型擬合的越好,否則,說明還有一些因素模型未能考慮。

  • python實現:
# Plot residual errors
residuals = pd.DataFrame(model_fit.resid)
fig, ax = plt.subplots(1,2)
residuals.plot(title="Residuals", ax=ax[0])
residuals.plot(kind='kde', title='Density', ax=ax[1])
plt.show()

模型擬合

# Actual vs Fitted
model_fit.plot_predict(dynamic=False)
plt.show()

模型預測

除了在訓練數據上擬合,一般都會預留一部分時間段作為模型的驗證,這部分時間段的數據不參与模型的訓練。

from statsmodels.tsa.stattools import acf

# Create Training and Test
train = df.value[:85]
test = df.value[85:]

# Build Model
# model = ARIMA(train, order=(3,2,1))  
model = ARIMA(train, order=(1, 1, 1))  
fitted = model.fit(disp=-1)  

# Forecast
fc, se, conf = fitted.forecast(15, alpha=0.05)  # 95% conf

# Make as pandas series
fc_series = pd.Series(fc, index=test.index)
lower_series = pd.Series(conf[:, 0], index=test.index)
upper_series = pd.Series(conf[:, 1], index=test.index)

# Plot
plt.figure(figsize=(12,5), dpi=100)
plt.plot(train, label='training')
plt.plot(test, label='actual')
plt.plot(fc_series, label='forecast')
plt.fill_between(lower_series.index, lower_series, upper_series, 
                 color='k', alpha=.15)
plt.title('Forecast vs Actuals')
plt.legend(loc='upper left', fontsize=8)
plt.show()

這是在ARIMA(1,1,1)下的預測結果,給出了一定的序列變化方向,看上去還是可以的。不過所有的預測值,都在真實值以下,所以還可以試試看有沒有別的更好的階數組合。
其實如果嘗試用ARIMA(3,2,1)會發現預測的更好:

AUTO ARIMA

通過預測結果來推斷模型階數的好壞畢竟還是耗時耗力了些,一般可以通過計算AIC或BIC的方式來找出更好的階數組合。pmdarima模塊的auto_arima方法就可以讓我們指定一個階數上限和信息準則計算方法,從而找到信息準則最小的階數組合。

from statsmodels.tsa.arima_model import ARIMA
import pmdarima as pm

df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/wwwusage.csv', names=['value'], header=0)

model = pm.auto_arima(df.value, start_p=1, start_q=1,
                      information_criterion='aic',
                      test='adf',       # use adftest to find optimal 'd'
                      max_p=3, max_q=3, # maximum p and q
                      m=1,              # frequency of series
                      d=None,           # let model determine 'd'
                      seasonal=False,   # No Seasonality
                      start_P=0, 
                      D=0, 
                      trace=True,
                      error_action='ignore',  
                      suppress_warnings=True, 
                      stepwise=True)

print(model.summary())

# Forecast
n_periods = 24
fc, confint = model.predict(n_periods=n_periods, return_conf_int=True)
index_of_fc = np.arange(len(df.value), len(df.value)+n_periods)

# make series for plotting purpose
fc_series = pd.Series(fc, index=index_of_fc)
lower_series = pd.Series(confint[:, 0], index=index_of_fc)
upper_series = pd.Series(confint[:, 1], index=index_of_fc)

# Plot
plt.plot(df.value)
plt.plot(fc_series, color='darkgreen')
plt.fill_between(lower_series.index, 
                 lower_series, 
                 upper_series, 
                 color='k', alpha=.15)

plt.title("Final Forecast of WWW Usage")
plt.show()

從輸出可以看到,模型採用了ARIMA(3,2,1)的組合來預測,因為該組合計算出的AIC最小。

如何自動構建季節性ARIMA模型?

如果模型帶有季節性,則除了p,d,q以外,模型還需要引入季節性部分:

與非季節性模型的區別在於,季節性模型都是以m為固定周期來做計算的,比如D就是季節性差分,是用當前值減去上一個季節周期的值,P和Q和非季節性的p,q的區別也是在於前者是以季節窗口為單位,而後者是連續時間的。
上節介紹的auto arima的代碼中,seasonal參數設為了false,構建季節性模型的時候,把該參數置為True,然後對應的P,D,Q,m參數即可,代碼如下:

# !pip3 install pyramid-arima
import pmdarima as pm
# Seasonal - fit stepwise auto-ARIMA
smodel = pm.auto_arima(data, start_p=1, start_q=1,
                         test='adf',
                         max_p=3, max_q=3, m=12,
                         start_P=0, seasonal=True,
                         d=None, D=1, trace=True,
                         error_action='ignore',  
                         suppress_warnings=True, 
                         stepwise=True)
smodel.summary()

注意這裏的stepwise參數,默認值就是True,表示用stepwise algorithm來選擇最佳的參數組合,會比計算所有的參數組合要快很多,而且幾乎不會過擬合,當然也有可能忽略了最優的組合參數。所以如果你想讓模型自動計算所有的參數組合,然後選擇最優的,可以將stepwise設為False。

如何在預測中引入其它相關的變量?

在時間序列模型中,還可以引入其它相關的變量,這些變量稱為exogenous variable(外生變量,或自變量),比如對於季節性的預測,除了之前說的通過加入季節性參數組合以外,還可以通過ARIMA模型加外生變量來實現,那麼這裏要加的外生變量自然就是時間序列中的季節性序列了(通過時間序列分解得到)。需要注意的是,對於季節性來說,還是用季節性模型來擬合比較合適,這裏用外生變量的方式只是為了方便演示外生變量的用法。因為對於引入了外生變量的時間序列模型來說,在預測未來的值的時候,也要對外生變量進行預測的,而用季節性做外生變量的方便演示之處在於,季節性每期都一樣的,比如年季節性,所以直接複製到3年就可以作為未來3年的季節外生變量序列了。


def load_data():
    """
    航司乘客數時間序列數據集
    該數據集包含了1949-1960年每個月國際航班的乘客總數。
    """
    from datetime import datetime
    date_parse = lambda x: datetime.strptime(x, '%Y-%m-%d')
    data = pd.read_csv('https://www.analyticsvidhya.com/wp-content/uploads/2016/02/AirPassengers.csv', index_col='Month', parse_dates=['Month'], date_parser=date_parse)
    # print(data)
    # print(data.index)
    ts = data['value']
    # print(ts.head(10))
    # plt.plot(ts)
    # plt.show()
    return ts,data

# 加載時間序列數據
_ts,_data = load_data()
# 時間序列分解
result_mul = seasonal_decompose(_ts[-36:],  # 3 years
                                model='multiplicative',
                                freq=12,
                                extrapolate_trend='freq')
_seasonal_frame = result_mul.seasonal[-12:].to_frame()
_seasonal_frame['month'] = pd.to_datetime(_seasonal_frame.index).month
# seasonal_index = result_mul.seasonal[-12:].index
# seasonal_index['month'] = seasonal_index.month.values
print(_seasonal_frame)
_data['month'] = _data.index.month
print(_data)
_df = pd.merge(_data, _seasonal_frame, how='left', on='month')
_df.columns = ['value', 'month', 'seasonal_index']
print(_df)
print(_df.index)
_df.index = _data.index  # reassign the index.
print(_df.index)

build_arima(_df,_seasonal_frame,_data)

# SARIMAX Model
sxmodel = pm.auto_arima(df[['value']],
						exogenous=df[['seasonal_index']],
						start_p=1, start_q=1,
						test='adf',
						max_p=3, max_q=3, m=12,
						start_P=0, seasonal=False,
						d=1, D=1, trace=True,
						error_action='ignore',
						suppress_warnings=True,
						stepwise=True)
sxmodel.summary()
# Forecast
n_periods = 36
fitted, confint = sxmodel.predict(n_periods=n_periods,
								  exogenous=np.tile(seasonal_frame['y'].values, 3).reshape(-1, 1),
								  return_conf_int=True)
index_of_fc = pd.date_range(data.index[-1], periods = n_periods, freq='MS')
# make series for plotting purpose
fitted_series = pd.Series(fitted, index=index_of_fc)
lower_series = pd.Series(confint[:, 0], index=index_of_fc)
upper_series = pd.Series(confint[:, 1], index=index_of_fc)

# Plot
plt.plot(data['y'])
plt.plot(fitted_series, color='darkgreen')
plt.fill_between(lower_series.index,
				 lower_series,
				 upper_series,
				 color='k', alpha=.15)

plt.title("SARIMAX Forecast of a10 - Drug Sales")
plt.show()

以下是結果比較:

  • 選擇ARIMA(3,1,1)來預測:
  • 選擇季節性模型SARIMA(3,0,1),(0,1,0,12)來預測:
  • 選擇帶季節性外生變量的ARIMA(3,1,1)來預測:

ok,本篇就這麼多內容啦~,下一篇將基於一個實際的例子來介紹完整的預測實現過程,感謝閱讀O(∩_∩)O。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

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

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

架構思考-業務快速增長時的容量問題

背景

之前做過一個項目,數據庫存儲採用的是mysql。當時面臨着業務指數級的增長,存儲容量不足。當時採用的措施是

 

1>短期解決容量的問題

mysql從5.6升級5.7,因為數據核心且重要,數據庫主從同步採用的是全同步, 利用5.7并行複製新特性,減少了主從同步的延遲,提高了吞吐量。

 

當時業務量高峰是2000TPS,5.6時可承受的最大TPS是3000,升級到5.7壓測可承受的最大TPD是5000.

 

2>流量拆分,從根本上解決容量問題

首先進行容量評估,通過對於業務開展規劃、活動預估,年底的容量會翻5倍。由於目前指數級增長的特性,數據庫要預留至少4倍的冗餘。

 

要對數據庫進行擴容,因為我們已經使用的是最頂配的SSD物理機了,就算可以在linux內核層面對numa進行綁核和非綁核等測試調參優化性能,提升容量也很有限。注意:一般的業務系統numa綁核會提高性能,但是mysql等數據庫系統是相反的。

 

所以垂直擴容不成功,就看看是否可以拆分流量。mysql流量拆分方式有x軸拆分(水平拆分)、y軸拆分(垂直拆分)、z軸拆分。

 

其中y軸拆分(垂直拆分)就是目前都在說做垂直領域,就是在一個細分領域里做深入的意思。由此可以很容易的記住垂直拆分的意思就是按照業務領域進行拆分,專庫專用。實際上能按領域拆分是最理想的,因為這種拆分業務清晰;拆分規則明確;系統之間整合或擴展容易。但是因為當時的業務已經很簡單,y軸拆分已經沒有什麼空間,這種拆分不能達到擴容20倍的目的。

 

z軸拆分近幾年沒有聽說過了,實際上大家也一直在用。這種方式是將一張大表拆分為子母表,就是分為概要信息和詳細信息。這種拆分方式對解決容量問題意義不大。

 

比較可行的一個方案是水平拆分。就是常說的分庫分表。按照容量評估,數據庫水平拆分一拆十,根據業務特點找一個標準字段來進行取模。

 

水平拆分一個技術點在於新老切換。

採用的是數據庫雙寫的方式,採用異步確保性的補償型事務,發送實時和延遲兩個MQ,通過開關來控制以老數據為準還是新數據庫為準。開始時以老數據庫為準,觀察新老數據沒有一致性問題之後,在一個低峰期,關閉了系統入口,等數據庫沒有任何變更之後切換開關,再打開系統入口。

 

問題

對於容量問題,上面採用的是一次性拆分到位的方法。對於一個規模稍大的公司來講,10組物理機(1組包含1主N從)的成本還好。

1>如果量級再次升級,需要每周增加10台數據庫才能支撐容量呢?

2>並且對系統可用性還有強要求,1s的停機都不可以接受呢?

 

解決方案分析

垂直流量拆分

首先我要分析的是每周增加10台數據庫這個容量是不是合理的。是否存在放大效應或者說可以減少對mysql這種昂貴資源的使用,轉為增加對HBase、Elasticsearch這種低成本高擴展性資源的使用呢?

 

基於這個思路,我們需要梳理下是否有可垂直拆分的流量。比如正向流量和負向流量。所謂正向流量是指比如交易下單,負向流量就是取消訂單,包括已付款取消、未付款取消、已到貨取消、未到貨取消等等。實際上負向流量在總訂單里佔比很少,但是業務要比正向交易業務複雜。將正向和逆向拆分的一個主要優勢是分治思想,可以降低兩部分各自的複雜度。將流量拆分重心轉移到正向流量上。

 

對於正向流量,一個業務比較常用的流量拆分思路是CQRS命令查詢分離,也就是常說的讀寫分離。如果讀流量大於寫流量。可以考慮能否將讀流量進一步拆分。拆分成實時和離線,將實時性要求不高的查詢走ES。ES的數據可以通過同步binlog變更獲得。

 

另外一個思路是將數據庫按照歷史數據來拆分。就是數據庫里只保存一定時間內的實時數據。超過指定時間則進行數據歸檔。將數據歸檔到HBase等,一般對於歷史的查詢實時性要求也不是很高。

 

垂直流量拆分可能遇到的問題

以上方法都是只考慮問題1如果量級再次升級,需要每周增加10台數據庫才能支撐容量的方案。如果再考慮問題2並且對系統可用性還有強要求,1s的停機都不可以接受。就需要看上述方案可能會遇到的問題。

 

拆分正向流量和負向流量、CQRS都需要改造,改造過程就需要過渡。過渡可以採用上面說的雙寫方式,觀察運行情況進行切換。切換過程中也可以不關閉流量。

 

麻煩的是數據歸檔。因為數據歸檔后刪除數據庫的數據,變更生效時,針對innodb來說,意味着數據結構重建,頻繁IO。這會影響OLTP在線事務的處理。可以考慮按表來歸檔,控制操作頻率,控制單位時間內對IO的影響。

 

分佈式關係型數據庫

分佈式關係型數據庫本質上是通過增加代理等方式將分庫分表做的更加隱蔽。

 

阿里巴巴分佈式關係數據庫(DRDS),前身是淘寶分佈式數據層(TDDL),核心就是用於分庫分表管理的代理層,宣稱可實現平滑擴容。

 

 

擴容過程實際是物理數據遷移的過程,引擎層按照分庫遷移后的邏輯先在物理節點上建立新的分庫,然後保留一個時間點進行全量的數據遷移。完成全量遷移后,開始基於先前保留的時間點進行增量的數據追趕。當增量數據追趕到兩邊的數據幾乎一致時,對數據庫進行瞬時停寫,將最後的數據追平,引擎層進行分庫邏輯的路由切換,路由規則切換完成后就完成了核心的擴容邏輯,整個切換過程在毫秒級別完成。

 

因為整個過程是毫秒級,所以可以做到業務層沒有感知,等多就是看到擴容過程中請求延時增加了不到1s。從原理上來說是可行的。

 

NOSQL解決方案

像這麼大的數據量一個很好的參考是12306。12306採用的是Geode。它是有數據庫功能的內存數據網格(In-Memory Data Grid,IMDG)。其重要特性是

 

1)集群內存總容量,現在Geode可以實現單個節點200-300GB內存,總集群包含300個節點的大型集群,因此總容量可以達到90TB左右的級別。

 

2)Geode集群功能非常強大,實現了內存中數據Shard分佈,自動管理,集群故障自動恢復,自動平均分佈等一系列企業級的功能,而且有自帶的集群間數據同步功能。

 

3)在CAP原理下(不了解的話可以百度一下CAP不可能三角),Geode可以保證集群內數據的強一致性,注意是真正的強一致性而不是最終一致性,再加上分區可用性,因此是一個CP型的產品,可以提供統一的數據視圖,支持高併發下的acid事務。

 

採用新的解決方案最大問題是平滑過渡,平滑過渡方面我還是覺得上面提到的數據庫雙寫方式安全可靠。

 

系統共建的解決方案

如果達到我所說的量級,基本上在一個行業中是處於垄斷地位的。並不是一家純的互聯網公司。這種公司可以採用和互聯網大廠合作的方式、用已經有這方面經驗的大廠,來根據自己內部系統的特性共建一套合適自己的定製化數據庫。

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

※台北網頁設計公司全省服務真心推薦

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

※推薦評價好的iphone維修中心

UniRx精講(二):獨立的 Update &UniRx 的基本語法格式

獨立的 Update

在 UniRx 簡介的時候,筆者講了一種比較麻煩的情況:就是在 MonoBehaviour 的 Update 中摻雜了大量互相無關的邏輯,導致代碼非常不容易閱讀。

這種情況我們平時在項目開發中非常常見,代碼如下:

private void Update()
{
	if (A)
	{
		...
	}

	if (B)
	{
		...
		if (D)
		{
			...
		}
		else {}
	}

	switch (C)
	{
		...
	}

	if (Input.GetMouseButtonUp(0))
	{
		...
	}
}

Update 方法中代碼冗長,而且干擾視線,非常影響閱讀。

而使用 UniRx 則可以改善這個問題。

void Start()
{
	// A 邏輯,實現了 xx
	Observable.EveryUpdate()
			.Subscribe(_ => 
			{
				if (A)
				{
					...
				}
			}).AddTo(this);
	

	// B 邏輯,實現了 xx
	Observable.EveryUpdate()
			.Subscribe(_ =>
			{
				if (B)
				{
					...
					if (D)
					{
						...
					}
				else {}
				}
			}).AddTo(this);

	// C 邏輯,實現了 xx
	Observable.EveryUpdate()
			.Subscribe(_ =>
			{
				switch (C)
				{
					...
				}
			}).AddTo(this);

	// 鼠標點擊檢測邏輯
	Observable.EveryUpdate()
			.Subscribe(_ => {
			{
				if (Input.GetMouseButtonUp(0))
				{
					...
				}
			}).AddTo(this);
}

雖然在代碼長度上沒有任何改善,但是最起碼,這些 Update 邏輯互相之間獨立了。
狀態跳轉、延時等等這些經常在 Update 里實現的邏輯,都可以使用以上這種方式獨立。

使用 UniRx 可以對我們工程中的代碼進行了改善,而筆者接觸 UniRx 之後,就再也沒有使用過 Update 方法了。

不過以上的這種 UniRx 使用方式,是比較初級的,而這種使用方式,隨着對 UniRx 的深入學習,也會漸漸淘汰,因為等我們入門之後,會學習更好的實現方式。

今天的內容就這些。

知識地圖

UniRx 的基本語法格式

在之前的兩篇文章中,我們學習了 UniRx 的 Timer 和 Update 這兩個 API,但是對代碼的工作原理還沒有進行過介紹。在這篇文章中,我們就來試着理解一下 UniRx 的代碼工作原理及 UniRx 的基本語法格式。

先搬出來第一篇文章中 Delay 的實現代碼:

/****************************************************************************
 * http://liangxiegame.com liangxie
 ****************************************************************************/
 
using System;
using UniRx;
using UnityEngine;

namespace UniRxLesson
{
	public class DelayExample : MonoBehaviour
	{
		private void Start()
		{
			Observable.Timer(TimeSpan.FromSeconds(2.0f)).Subscribe(_ =>
			{
				Debug.Log("延時兩秒"); 
				
			}).AddTo(this);
		}
	}
}

代碼中的 Observable.XXX().Subscribe() 是非常經典的 UniRx 格式。只要理解了這種格式就可以看懂大部分的 UniRx 的用法了。

首先解決代碼中的詞彙問題:

  • Observable:可觀察的,是形容詞,它形容後邊的詞(Timer)是可觀察的,我們可以直接把 Observable 後邊的詞理解成發布者。
  • Timer:定時器,名詞,被 Observable 修飾,所以是發布者,是事件的發送方。
  • Subscribe:訂閱,是動詞,它訂閱誰呢?當然是前邊的 Timer,這裏可以理解成訂閱者,也就是事件的接收方。
  • AddTo:添加到,這個我們暫時不用理解得太深刻,只需要知道它是與 MonoBehaviour 進行生命周期綁定即可。

以上的代碼,連起來則是:可被觀察(監聽)的.Timer().訂閱()
理順了之後應該是:訂閱可被觀察的定時器。

其概念關係很容易理解。

  • Timer 是可觀察的。
  • 可觀察的才能被訂閱。
Observable.XXX().Subscribe();

這行代碼我們可以理解為:可被觀察(監聽)的 XX,註冊。

以上筆者從發布者和訂閱者這個角度進行了簡單的介紹,以便大家理解。
但是 UniRx 的側重點,不是發布者和訂閱者這兩個概念如何使用,而是事件從發布者到訂閱者之間的過程如何處理。
所以這兩個點不重要,重要的是兩點之間的線,也就是事件的傳遞過程。

這裏先不說得太深入,在入門之後,會用很大的篇幅去深入介紹這些概念的。

今天的 UniRx 的基本語法格式的介紹就到這裏,我們下一篇再見,拜拜~

知識地圖

更多內容
QFramework 地址:https://github.com/liangxiegame/QFramework
QQ 交流群:623597263
涼鞋的主頁:https://liangxiegame.com/zhuanlan
關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

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

【其他文章推薦】

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

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

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

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

※教你寫出一流的銷售文案?

※超省錢租車方案

【溫故知新】 編程原則和方法論

寫了這麼多年代碼,依舊做不好一個項目

做好一個項目是人力、產品、業務、技術、運營的結合,可能還疊加一點時機的因素,就我們碼農而言,工作就是搬磚,實現產品, 給業務提供支撐。
“給祖傳代碼加 BUG 修 BUG”,“拿起鍵盤一把梭”這些戲謔程序員的話,聽多了真的會讓程序員麻木,彷彿大家都是這麼乾的。
從業多年,堆過 shi 山,接手過祖傳代碼, 已經不能沉下氣去查看、調試 shi 山代碼, 說實話,很累。
本人一直推崇寫流暢、自然、可自解釋的代碼,讓優雅成為一種習慣, 給自己留個念想、給後人留個好評。

溫故而知新,聊一聊現代編程幾大常見的編程原則

普世原則
KISS (Keep It Simple Stupid) 保持系統結構簡單可信賴
YAGNI (you aren’t gonna need it) 當前確實需要,再去做
Do The Simplest Things That Could Possibly Work 思考最簡單可行的辦法
Separation of Concerns 關注點分離
Keep Things DRY 保持代碼結構清爽 Don’t repeat yourself
Code For The Maintainer 站在維護者角度寫代碼
Avoid Premature Optimization 避免提前優化
Boy-Scout Rule 清掃戰場:清理口水話註釋、無效代碼
模塊(類)間
Minimise Coupling 低耦合
Law of Demeter Don’t talk to strangers,對象方法只接觸該接觸的對象、字段、入參
Composition Over Inheritance 組合而不是繼承
Orthogonality 正相關,概念上不相關的事物不應在系統中強行相關
Robustness Principle 代碼健壯性
Inversion of Control 控制反轉
模塊(類)
Maximise Cohesion 高內聚
Likov Substitution Principle 里斯替代原則:將程序中對象替換到子類型實例,不會報錯。
Open/Closed Principle 設計的實體對擴展開放,對修改關閉
Single Responsiblity Principle 單一責任原則
Hide Implementation Details 隱藏實施細節
Curly’s Law 柯里定律:為確定目標編寫特定代碼
Encapsulate What Changes 封裝變化
Interface Segregation Principle 接口隔離原則
Command Query Separation 命令查詢分離

KISS
大多數系統保持簡單,會運行的很好。

  • 更少的代碼消耗更好的時間,產生更少的 bug,並且容易修改
  • 複雜業務都是由簡單代碼堆砌而成
  • 完美並不是“沒有什麼東西可以再加”,而是“沒有什麼東西可以被去掉”

YAGNI
YAGNI 代表“you aren’t gonna need it.”,不要自以為是的提前實現某些邊角,直到真正需要的時候,再來做。

  • 提前做明天才需要做的工作,意味着當前迭代中需要花費更多精力
  • 導致代碼膨脹,軟件變得臃腫且複雜

Separation of Concerns
關注點分離是一種將計算機程序分為不同部分的設計原則,這樣每個部分都可以解決一個單獨的關注點。例如應用程序的業務邏輯是一個問題,而用戶界面是另外一個問題,更改用戶界面不應要求更改業務邏輯,反之亦然。

  • 簡化應用程序的開發和維護
  • 如果關注點分離得很好,則各個部分可以重複使用,也可以獨立開發和更新。

Interface Segregation Principle
接口隔離,將胖接口修改為多個小接口,調用接口的代碼應該比實現接口的代碼更依賴於接口。
why:
如果一個類實現了胖接口的所有方法(部分方法在某次調用時並不需要),那麼在該次調用時我們就會發現此時出現了(部分並不需要的方法),而並沒有機制告訴我們我們現在不應該使用這部分方法。
how: 避免胖接口,類永遠不必實現違反單一職責原則的接口。可以根據實際多職責劃分為多接口,類實現多接口后, 在調用時以特定接口指代對象,這樣這個對象只能體現特定接口的方法,以此體現接口隔離。

   public interface IA
    {
        void getA();
    }

    interface IB
    {
        void getB();
    }

    public class Test : IA, IB
    {
        public string Field { get; set; }
        public void getA()
        {
            throw new NotImplementedException();
        }

        public void getB()
        {
            throw new NotImplementedException();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            IA a = new Test();
            a.getA();       //  在這個調用處只能看到接口IA的方法, 接口隔離
        }
    }

Command Query Separation
命令查詢分離: 操作方法就只寫操作邏輯,查詢方法就只寫查詢邏輯,並以明顯的方法名區分自己的動作。
有了這個原則,程序員可以更加自信地進行編碼:由於查詢方法不會改變狀態,因此可以在任何地方以任何順序使用,使用操作方法時,也心中有數。

End

懂得這麼多道理,卻依舊過不好這一生。前人總結的編程原則和方法論需要在實踐中感悟,束之高閣,則始終不能體會編程的魅力和快感

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

【其他文章推薦】

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

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

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

Spring系列.AOP使用

AOP簡介

利用面向對象的方法可以很好的組織代碼,也可以繼承的方式實現代碼重用。但是項目中總是會出現一些重複的代碼,並且不太方便使用繼承的方式把他們重用管理起來,比如說通用日誌打印,事務處理和安全檢查等。我們可以將這些代碼封裝起來,做成通用模塊,但是還是需要在代碼中每處需要的地方進行显示調用,使用起來不方便。這是時候就是利用AOP的時候。

AOP是一種編程範式,用來解決特定的問題,不能解決所有問題,可以看做是OOP的補充,常見的編程範式還有:

  • 面向過程編程;
  • 面向對象編程;
  • 面向函數編程(函數式編程);
  • 事件驅動編程(GUI開發中比較常見);
  • 面向切面編程

AOP的常見使用場景

  • 性能監控,在方法調用前後記錄調用時間,方法執行太長或超時報警;
  • 緩存代理,緩存某方法的返回值,下次執行該方法時,直接從緩存里獲取;
  • 軟件破解,使用AOP修改軟件的驗證類的判斷邏輯;
  • 記錄日誌,在方法執行前後記錄系統日誌;
  • 工作流系統,工作流系統需要將業務代碼和流程引擎代碼混合在一起執行,那麼我們可以使用AOP將其分離,並動態掛接業務;
  • 權限驗證,方法執行前驗證是否有權限執行當前方法,沒有則拋出沒有權限執行異常,由業務代碼捕捉;
  • 事務處理 。

Spring AOP相關概念

  • AOP:這種在運行時(或者編譯時或者加載時),動態地將某些公共代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程;
  • 切面(Aspect):A modularization of a concern that cuts across multiple classes。在Spring中切面就是一個標註@AspectJ的類,不要想得太複雜;
  • 連接點(Joinpoint):方法執行過程中的某個點,是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,並添加新的行為;
  • 通知(advice):描述切面要完成什麼工作,以及在什麼時間點進行工作;
  • Pointcut:用來匹配一組連接點,並且pointcut會關聯advice,在pointcut匹配的連接點執行的時候,advice代碼會被執行;
  • Introduction
  • Target object:被織入切面的對象;
  • AOP proxy : 包裝了切面代碼和target代碼的對象,Spring中支持JDK動態代理和
    CGLIB,默認使用JDK動態代理,但是如果被代理的類沒有實現接口,或者用戶強制使用CGLIB,那麼Spring會使用CGLIB代理;
  • Weaving:將切面代碼添加到目標代碼的過程,織入的類型有編譯時織入,加載時織入和運行時織入(Spring是運行時織入)

SpringAOP可以應用5種類型的通知:

  • 前置通知(Before):在目標方法被調用之前調用通知功能。
  • 後置通知(After):在目標方法完成之後調用通知,此時不會關心方法的輸出是什麼。(不管執行是否成功都執行都執行)
  • 返回通知(After-returning):在目標方法成功執行之後調用通知。
  • 異常通知(After-throwing):在目標方法拋出異常后調用通知。
  • 環繞通知(Around):通知包裹了被通知的方法,在被通知的方法調用之前和調用之後執行自定義的行為。

Spring AOP相關

開啟Aop


//自動選擇合適的AOP代理
//傳統xml這樣配置:<aop:aspectj-autoproxy/>

//exposeProxy = true屬性設置成true,意思是將動態生成的代理類expose到AopContext的ThreadLocal線程
//可以通過AopContext.currentProxy();獲取到生成的動態代理類。

//proxyTargetClass屬性設置動態代理使用JDK動態代理還是使用CGlib代理,設置成true是使用CGlib代理,false的話是使用JDK動態代理

//注意:如果使用Spring Boot的話,下面的配置可以不需要。AopAutoConfiguration這個自動配置類中已經自動開啟了AOP
//默認使用CGLIB動態代理,Spring Boot配置的優先級高於下面的配置

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = false)
public class AopConfig {

}


如果使用傳統的配置方式的話,可按如下配置開啟AOP功能。

<aop:aspectj-autoproxy/>

定義一個Aspect

Aspects (classes annotated with @Aspect) can have methods and fields, the same as any other class. They can also contain pointcut, advice, and introduction (inter-type) declarations.

可以使用普通Bean的定義方式,或者加@Aspect註解的方式定義。一旦一個類被標註成切面類,它就不會成為其他切面的代理對象。

定義一個PointCut

切面表達式可以由指示器,通配符和運算符組成

  1. 指示器(Designators)
  • 匹配方法 execution() (重點掌握…)
  • 匹配註解 @target() @args() @within() @annotation()
  • 匹配包/類型 within()
  • 匹配對象 this() bean() target()
  • 匹配參數 args()
  1. Wildcards(通配符)
  • *匹配任意數量的字符
  • +匹配指定類及其子類
  • .. 一般用於匹配任意參數的子包或參數
  1. Operators(運算符)
  • && 與操作符
  • || 或操作符
  • ! 非操作符

下面給出一個定義PointCut的例子

package com.csx.demo.spring.boot.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {

    //PointCut匹配的方法必須是Spring中bean的方法
    //Pointcut可以有下列方式來定義或者通過&& || 和!的方式進行組合.
    //下面定義的這些切入點就可以通過&& ||組合

    private static Logger logger = LoggerFactory.getLogger(MyAspect.class);

    //*:代表方法的返回值可以是任何類型
    //整個表達式匹配controller包下面任何的的echo方法,方法入參樂意是任意
    @Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(..))")
    public void pointCut1(){}

    //代表echo方法必須有一個參數 參數的類型可以是任意類型
    @Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(*))")
    public  void pointCut2(){}

    //代表echo方法必須有兩個參數,第一個類型任意,第二個類型必須是String
    @Pointcut("execution(* com.csx.demo.spring.boot.controller.*.echo(*,String))")
    public void pointCut3(){}

    //contrller包及其子包下面的任意類的任意方法
    //需要注意的是with和@with都是正對包級別的
    @Pointcut("within(com.csx.demo.spring.boot.controller..*)")
    public void pointCut4(){}

    //使用RestController這個註解標註任意類的任意方法
    @Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
    public void pointCut5(){}

    //用法和@Within類似
    @Pointcut("@target(org.springframework.web.bind.annotation.RestController)")
    public void pointCut10(){}

    //MyService這個接口實現類的任何方法
    //如果MyService是一個類的話,那匹配這個類內部的所有方法
    @Pointcut("this(com.csx.demo.spring.boot.service.MyService)")
    public void pointCut6(){}

    @Pointcut("this(com.csx.demo.spring.boot.service.MyServiceImpl)")
    public void pointCut7(){}

    //某個bean內部的所有方法
    @Pointcut("bean(myServiceImpl)")
    public void pointCut8(){}

    //@within和@target針對類的註解,@annotation是針對方法的註解
    //匹配任何標註GetMaping註解的方法
    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void pointCut9(){}

    //匹配只有一個參數,參數類型是String的方法
    @Pointcut("args(String)")
    public void pointCut11(){}


    @Before("pointCut1()")
    public void befor(){
        logger.info("前置通知vvvv...");
        logger.info("我要做些事情...");
    }

    @After("pointCut1()")
    public void after(){
        logger.info("後置通知");
    }

    @AfterReturning("pointCut1()")
    public void afterReturn(){
       logger.info("後置返回");
    }

     //目標方法拋出相關異常后通知
    @AfterThrowing("pointCut1()")
    public void afterThrowing(){
        logger.info("後置異常");
    }

    @Around("pointCut1()")
    public void around(ProceedingJoinPoint point) throws Throwable {
        logger.info("環繞通知...");
        logger.info("我要做些事情...");
        point.proceed();
        logger.info("結束環繞通知");
    }

}

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

【其他文章推薦】

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

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

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?