分類: 3C資訊

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

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

    可是,要完成這一次挑戰,我必須要有一台車。這次和我一起挑戰的,是全新昂科威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/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

    ※超省錢租車方案

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

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

  • 大尺寸+高配置 眾泰T800 13.98萬起售

    大尺寸+高配置 眾泰T800 13.98萬起售

    4英寸中控屏第一時間抓住你的眼球,全車的功能基本都集成在裏面,旋鈕式換擋,全液晶儀錶,大面積軟性材料的包裹,檔次感還是營造的不錯,雖然說中控UI界面布局和反應速度還有提升的空間,但結合其價格來看,也能讓你產生“要啥自行車”的感慨了。

    眾泰T800在5月8日晚正式上市,新車共推出五款車型,售價13.98-18.58萬元。T800作為眾泰首款七座中型SUV,其配置同尺寸都達到了品牌的新高度。動力總成為2.0T+6DCT,從某種角度上T800可視作T700的加長版本。

    眾泰T800在外觀設計上可以說擁有相當高的原創度,前臉進氣格柵的面積非常大,採用星空點陣的設計元素,下部格柵採用了中國風的回紋設計,凸顯了整個正臉的設計感。頭燈部分採用了全LED光源,轉向燈則單獨設計在下部,同樣使用了LED,只有最下面的霧燈為鹵素光源,配置上十分厚道。

    T800的整車尺寸為4910x1933x1735mm,軸距2850mm,在目前自主中型七座SUV中算比較大的,側門上用裝飾模擬了出風口的造型,並且還點綴有眾泰漢語拼音首字母“Z”字形的標誌,同時不忘加入一個裝飾燈,這樣的小心思在其它品牌上不多見。還了解到,T800的頂配車型搭載了電吸門,在這個級別中是獨一份的那個。

    進入車內,10.4英寸中控屏第一時間抓住你的眼球,全車的功能基本都集成在裏面,旋鈕式換擋,全液晶儀錶,大面積軟性材料的包裹,檔次感還是營造的不錯,雖然說中控UI界面布局和反應速度還有提升的空間,但結合其價格來看,也能讓你產生“要啥自行車”的感慨了。

    談到眾泰,怎能不提配置,T800的配置水平用“極限”形容毫不過分,全景天窗,360°影像這些只是基本操作,什麼電動腳踏,電吸門,氛圍燈,車聯網,前窗加熱······配置上堆的滿滿噹噹,重要的是,除了入門車型以外,很多配置都實現了全系覆蓋,可以說,T800隻要不買最低配,都可以達到越級體驗。

    T800的2.0T動力,參數上達到了170kW/350N·m,在自主眾多中型七座中屬於動力靠前的那個,匹配六速雙離合變速箱,或許表現上沒有眾多愛信6AT那麼出色,但想想車內那麼豐富的配置,也能理解。前麥弗遜+后多連桿懸架是這個級別的標配,沒有四驅車型有些遺憾。但考慮其“城市SUV”的身份,也不會是什麼大問題。

    對於T800,我們先拋開眾泰眾多的“歷史遺留問題”去看待它。設計有原創,配置高上天,價格有驚喜——這三點已經是很大的亮點。自主品牌中型七座SUV已經很多,但T800還是能找到獨特的競爭力。能不能賣爆款不好說,但還是能吸引部分消費者的眼球,至少我們能看到的,T800已經是眾泰拿出最大的誠意去做的產品。品牌和質量都是需要長時間積累的事情,眾泰想要像其他自主品牌一樣深入民心,還是有很長的路要走。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※超省錢租車方案

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

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

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

  • 7.99萬起,今天上市的大空間6座車真是家用好選擇!

    7.99萬起,今天上市的大空間6座車真是家用好選擇!

    尾部在擾流板、貫穿尾燈的鍍鉻裝飾、黑色塑料擋板的組合下,形成了一種層次感。敦厚的車尾部,更是讓它充滿安全感。仿木材料的中控台,還有一個大尺寸豎直中控屏幕,以及是手感極佳的平底式運動方向盤,它在簡約風格中加入一點運動的元素。

    “一輛車究竟是多少座位最好?”,除了自己,還有配偶,加上父母以及自己的孩子,或許還是雙胞胎,這樣看來起碼是6座車型,另外一般而言緊湊型轎車後排乘坐3成年人是比較難受的事情。

    正是為了滿足用戶這種需求,比亞迪宋MAX前期推出了7座車型,如今更是推出了6座車型,官方指導價為:7.99-12.99萬。那麼它表現如何呢?

    6座,就是它最大的不同

    6座版本的比亞迪宋max依然有着4680*1810*1680mm的車身尺寸,以及是能夠帶來充足空間表現的2785mm軸距。並且在座椅配置上一樣保留了7座車型的優點,諸如第三排寬大保護作用大的頭枕、座椅採用打孔真皮材質。

    它採用了2+2+2的6座布局,獨立第二排座椅可以帶來比7座車型更舒適的體驗,加上獨立的可調節座椅扶手,座椅包裹性更佳。中部通道寬度為190mm,乘客進出第三排更為優雅。

    在實際的乘坐它表現讓人滿意,前排以及第二排座椅包裹性極佳,並且頂配車型上前排座椅還具備主副駕座椅通風加熱、第二排預警限力安全帶等配置。唯獨是第三排由於車身結構問題坐墊與地板距離較近,腿部支撐較弱,中長途旅行中更適合乘坐小孩子或者是身材嬌小的成年人。

    設計以及配置,和7座車型無異

    6座版本的宋MAX在設計上和7座車型保持了一致,犀利大燈帶有的鍍鉻裝飾條以及LED日間行車燈和大尺寸進氣格柵橫向裝飾條連成一體,拉寬了視覺寬度。這個“大嘴”配上這兇狠犀利的大燈,就形成了它’Dragon Face”設計的基本元素。

    4680mm車身長度的它在逐漸下滑的懸浮式車頂襯托下,顯得車身相當修長,低矮的腰線則降低了它的視覺重心,讓它整體有着一種動感、衝勁。

    尾部在擾流板、貫穿尾燈的鍍鉻裝飾、黑色塑料擋板的組合下,形成了一種層次感。敦厚的車尾部,更是讓它充滿安全感。

    仿木材料的中控台,還有一個大尺寸豎直中控屏幕,以及是手感極佳的平底式運動方向盤,它在簡約風格中加入一點運動的元素。

    生產實力強大、自產自銷的比亞迪能夠有效控製成本,所以它在配置配備上相當慷慨,標配了ESp車身穩定系統、17英寸鋁合金輪轂、自動空調、遠程啟動等等。又或者是一些“跨級般”的配置,諸如選配的LED自動大燈。

    操控,或許可以說沉穩自信?

    比亞迪宋MAX全系車型採用前麥弗遜后扭力梁懸架,處於這個級別的主流水平。動力方面搭載了最大輸出功率154馬力的1.5T直噴發動機,匹配的是6MT或者6速雙離合變速箱。

    在日常使用中它整體表現出同價位中較高的水準,應付城市使用這套渦輪增壓+雙離合的動力總成顯得游刃有餘,能夠有效地控制轉速在1500rpm之中,需要提速的時候154馬力的底蘊讓超車動作比較從容,而且它1750rpm就開始進入240牛米的最大輸出扭矩區間,相比競爭對手們最大扭矩輸出更早。只是低速在1、2擋切換時會有絕大多數雙離合變速箱的小不足——輕微頓挫感。

    據比亞迪官方稱,比亞迪宋max有着前奔馳底盤調校工程師漢斯柯克參与調校,讓它更注重舒適性,所以宋max駕駛起來有着厚重的行駛質感。能夠過濾掉路面各種細碎振動的同時,還有讓人安心的高速穩定性。受制於全系搭配的液壓轉向助力,宋max轉向略有虛位,並不可以說是精準,幸好較強的懸架支撐帶來了較小的車身傾側,扳回了一城。

    總的來說,比亞迪宋max相比同價位對手有着不少的優勢,諸如更佳的底盤表現、更豐富的配置以及更出色的外觀,這恰恰迎合如今消費者開始接受這些“體面”MpV的用戶趨勢。6座車型,則是滿足了消費者不同的乘坐需求,多一種選擇未嘗不是一種好事。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

  • 6秒破百很厲害?國內10來萬買SUV更應該看這點!

    6秒破百很厲害?國內10來萬買SUV更應該看這點!

    值得說明的是,國內媒體測試的多為旱地剎車成績,而在售車型大多採用四季胎,在暴雨天氣下剎車距離或會明顯變長,所以各位在暴雨天氣下最好加長與前車距離。我們可以看到市面上多款SUV車型的100-0km/h剎停成績差異頗大,這也是因為大部分用戶對於剎車方面的關注度不高,導致廠家有出現“偷懶”情況。

    大家有沒有發現汽車廠家往往會把宣傳重點放在動力性能和發動機技術上,但是對於剎車性能往往置於末位。而只要您多加留意,就會和朗編一樣發現各個級別中不少熱點車型都以動力性能作為賣點!

    連柯迪亞克、途觀L和冠道這類型大尺寸的SUV車型都在極力宣傳動力性能,但這明顯是為迎合國內消費者喜好而做出的選擇,畢竟用戶大多認為動力表現能直接決定行駛的順暢感,或者說是快感!但是這份快感的權重能比得上行車安全性嗎?

    再者,我國的高速公路最高限速為120km/h,過多的發動機功率是否必要還有待商榷。

    而在我們日常行車過程中,能看見最多的車禍是啥?可能許多人會和朗編一樣會想到追尾事故,四車連環追尾、六車連環追尾等事故經常霸佔着新聞的首頁版面,而且在雨霧天氣,追尾事故發生的幾率也將大幅度上升。

    而據之前相關的統計數據显示,汽車追尾在整個道路交通事故中約佔70%以上,造成追尾事故自然有一部分是駕駛員意識、駕駛技術的原因,同時也有一部分是駕駛員意識到位了但車輛的剎車性能不到位而造成的。

    現在銷售火爆的15萬級別合資/自主SUV車型它們是否注重剎車性能?

    值得說明的是,國內媒體測試的多為旱地剎車成績,而在售車型大多採用四季胎,在暴雨天氣下剎車距離或會明顯變長,所以各位在暴雨天氣下最好加長與前車距離!

    我們可以看到市面上多款SUV車型的100-0km/h剎停成績差異頗大,這也是因為大部分用戶對於剎車方面的關注度不高,導致廠家有出現“偷懶”情況。

    其實能影響剎車性能的元素有很多,除了輪胎規格、輪胎抓地力以外,還有剎車片和剎車盤的性能,剎車片和剎車盤的材料優劣,摩擦係數的大小都會直接影響到制動力的大小!

    而且值得注意的還有剎車分泵的活塞數量,一般家用車型每個分泵只有一個活塞,其性能自然沒有性能車身上的多活塞設計那般剎車力度大而且均勻。

    由此可見想要提升剎車性能其實是相當複雜而困難的,比較有效的方法是系統而專業地改裝剎車系統,這裏面包含了輪胎、剎車盤、剎車片、剎車分泵、剎車油等多個配件的升級。

    另外一個方法就是廠家在研發車輛時強化車輛剎車系統的調校,優化配件選材以提升原廠車的剎車表現,當然了這要投入更多成本,但是長遠來看,廠家若以優異的剎車性能來作為賣點招攬顧客的話,或會效果斐然!

    最後提點題外話,那就是歐洲人為什麼會這麼喜歡高爾夫GTI這一類小鋼炮車型?很重要的就是歐洲的某些高速公路限速更高,在高速區域剎車性能的重要性就完全體現出來了,對於安全性也有更明顯的影響!而咱們國內的汽車消費市場也應該對剎車性能有更高要求,從而倒逼廠家重視提升剎車性能!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

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

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

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

    用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維修中心

  • Jmeter(十) – 從入門到精通 – JMeter邏輯控制器 – 中篇(詳解教程)

    Jmeter(十) – 從入門到精通 – JMeter邏輯控制器 – 中篇(詳解教程)

    1.簡介

    Jmeter官網對邏輯控制器的解釋是:“Logic Controllers determine the order in which Samplers are processed.”。

    意思是說,邏輯控制器可以控制採樣器(samplers)的執行順序。由此可知,控制器需要和採樣器一起使用,否則控制器就沒有什麼意義了。放在控制器下面的所有的採樣器都會當做一個整體,執行時也會一起被執行。

    JMeter邏輯控制器可以對元件的執行邏輯進行控制,除僅一次控制器外,其他可以嵌套別的種類的邏輯控制器。

    2.邏輯控制器分類

    JMeter中的Logic Controller分為兩類:
    (1)控制測試計劃執行過程中節點的邏輯執行順序,如:Loop Controller、If Controller等;
    (2)對測試計劃中的腳本進行分組、方便JMeter統計執行結果以及進行腳本的運行時控制等,如:Throughput Controller、Transaction Controller。

    3.預覽邏輯控制器 

    首先我們來看一下JMeter的邏輯控制器,路徑:線程組(用戶)->添加->邏輯控制器(Logic Controller);我們可以清楚地看到JMeter5中共有17個邏輯控制器,如下圖所示:

    如果上圖您看得不是很清楚的話,宏哥總結了一個思維導圖,關於JMeter5的邏輯控制器類型,如下圖所示: 

     通過以上的了解,我們對邏輯控制器有了一個大致的了解和認識。下面宏哥就給小夥伴或則童鞋們分享講解一些通常在工作中會用到的邏輯控制器。 

    4.常用邏輯控制器詳解

      這一小節,宏哥就由上而下地詳細地講解一下常用的邏輯控制器。

    4.1Critical Section Controller

    我們先來看一下,官方原汁原味的解釋:The Critical Section Controller ensures that its children elements (samplers/controllers, etc.) will be executed by only one thread as a named lock will be taken before executing children of controller.

    宏哥這個二把刀的翻譯,給你們翻譯一下這段鳥語看看到底是什麼意思,大致意思是: Critical Section Controller(臨界區控制器),確保它的子元素(samplers /控制器等)在執行控制器的子程序之前只執行一個線程作為指定的鎖。呵呵!看到這句話是不是覺得一頭霧水啊,摸一摸自己所剩無幾的頭髮陷入沉思中…..沒有關係的,不要糾結了,宏哥後邊會用具體實例講解一下,看完實例后,再回過頭來閱讀這句話,你就會恍然大悟了。

     1、我們先來看看這個Critical Section Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > 臨界部分控制器,如下圖所示:

    2、關鍵參數說明如下:

    Name:名稱,可以隨意設置,甚至為空;

    Comments:註釋,可隨意設置,可以為空;

    Lock name:鎖名稱,這裏可以填入其子節點下執行的線程的名稱,這個線程作為一個全局鎖存在

    4.1.1實例講解 

    這部分主要是通過配合實例我們來理解一下開始那句話到底什麼意思。

    1、宏哥這裏先說一個訪問宏哥博客園的JMeter系列文章的測試場景:我們第一步首先要訪問博客園的首頁,第二步找到宏哥的訪問宏哥博客園的首頁,第三步點擊JMeter類別。按順序完成三步,才能完成這個測試場景。那麼我們根據這個場景用JMeter來添加多個請求的取樣器。如下圖所示:

    2、腳本調試是通了,運行JMeter,查看結果樹,如下圖所示:

    3、從上個圖,查看結果樹中显示請求結果數據不是按照順序請求,不符合預期,這個時候增加一個critical section controller(臨界部分控制器),增加一個鎖,就能控制執行順序。如下圖所示:

    4、腳本調試是通了,運行JMeter,查看結果樹,可以清楚地看出來是按預期的順序執行請求的。但是這樣響應時間會過長,這個後邊再做講解。如下圖所示: 

     4.1.2鎖名分類

    (1)鎖名為空,認為每個鎖為不同的鎖

    1、宏哥通過具體實例,來看一下,創建鎖名為空的臨界部分控制器,如下圖所示:

    2、運行JMeter,查看結果樹,如下圖所示:

    (2)鎖名相同,多個鎖認為是同一個鎖,同一個時間點只能存在一個運行中

    1、宏哥通過具體實例,來看一下,創建鎖名相同的臨界部分控制器,如下圖所示:

    2、運行JMeter,查看結果樹,如下圖所示:

    (3)鎖名為變量,根據變量值來判斷是不是屬於同一個鎖,變量值為相同時,則認為是同一個鎖

    1、宏哥通過具體實例,來看一下,創建鎖名為變量的臨界部分控制器,如下圖所示:

    2、運行JMeter,查看結果樹,如下圖所示:

    4.2ForEach Controller

    ForEach 控制器:一般搭配用戶變量使用。依次調用用戶定義的變量,直到最後一個,結束循環。為了滿足ForEach Controller提取數據,變量命名的格式一般為“變量名_数字”,其中数字從1開始。
    1、即遍歷循環控制器,顧名思義是定義一個循環規則。
    2、用來遍歷當前元素的所有可執行場景。
    3、在用戶自定義變量中讀取一系列相關的變量,該控制器下的採樣器或控制器都會被執行一次或多次,每次讀取不同的變量值。
    4、這個控制器一般配合配置元件 → 正則表達式提取器來一起使用,可對頁面上的某些元素進行重複處理。

    1、我們先來看看這個ForEach Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > ForEach控制器,如下圖所示: 

    2、關鍵參數說明如下:

    Name:名稱,可以隨意設置,甚至為空;

    Comments:註釋,可隨意設置,可以為空;

    Input variable prefix:輸入變量前綴,可以在“用戶自定義變量”中定義一組變量,循環控制器可以從中獲取到變量對應的值,然後作為循環控制器的循環條件,還可以輸出變量作為取樣器的參數。

    Start index for loop:循環變量下標起點。循環指數開始(唯一)→ 遍歷查詢的變量範圍,開始的值(這裏如果不填寫,默認從 1 開始,如果沒有 1 開始的變量,執行時會報錯)

    End index for loop:循環變量下標終點。循環指數結束(包含)→ 遍歷查詢的變量範圍,結束的值

    Output variable name:輸出變量名稱,循環控制器生成的變量名稱。後續可通過${}引用

    Add “_” before number ?: 變量前綴后是否加“_”作為分隔符。如果定義的變量名中有下劃線的話就要勾選此項,否則找不到;反之,沒有的話不要勾選,否則同樣找不到變量

    4.2.1實例講解

    1、首先在自定義5個前綴為 北京宏哥 的變量,值分別為 a b c d e。並且 北京宏哥 後面的数字是連續的,如果不連續,則不會被循環到,如下圖所示:

    2、配置ForEach控制器,如下圖所示:

    3、添加請求 訪問博客園首頁 + 輸出值:${宏哥},輸出值是在控制器的輸出變量 宏哥,通過 ${宏哥} 取到輸出變量的值,如下圖所示:

    4、添加查看結果樹,運行JMeter,查看結果樹,如下圖所示: 

    注意:敲黑板,敲腦袋!!!

    1、輸入變量的後綴數值一定要連續,比如 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 … 這樣,如果中間有不連續的,循環會中斷

    2、循環開始的設定:如果變量為北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而設定的開始為 1,則會從北京宏哥_2 開始循環

    3、循環結束的設定:如果變量有3個 北京宏哥_1, 北京宏哥_2, 北京宏哥_3,而設定的結束為5,則只會循環 北京宏哥_1, 北京宏哥_2, 北京宏哥_3 ,如果設定的結束為2,則會循環  北京宏哥_1, 北京宏哥_2 。

    4.3Include Controller

    Include控制器用來導入外部的測試片段(非完整的測試計劃),在執行時會執行導入的測試計劃,但是被導入的測試計劃有特殊要求,它不能有線程組,只能包含簡單的控制器及控制器下的元件。換句話說就是相當於加了一個執行單元,一個封裝了的業務操作單元,類似我們程序開發中的函數(方法)一樣。例如一個查詢學生信息的業務操作我們用取樣器來模擬,然後放到簡單控制器中作為一個執行單元,別的地方也要用到時,我們可以不用重複造輪子直接引用過來。

    一般來說,Include控制器和測試片段(Test Fragment)配合使用的比較常見。

    1、我們先來看看這個include Controller長得是啥樣子,路徑:線程組 > 添加 > 邏輯控制器 > Include控制器,如下圖所示:

    2、關鍵參數說明如下:

    Name:名稱,可以隨意設置,甚至為空;

    Comments:註釋,可隨意設置,可以為空;

    Filename:文件名,必輸字段,如果沒有,就會報錯。通過Filename的路徑和文件名引用外部的jmx文件。

    宏哥推薦小夥伴或者童鞋們可以將 Include控制器 Module控制器(傳送門)一起對比着學習,Include控制器 是從外部文件引用,只能引用整個測試片段的內容,Module控制器 是從內部文件中引用,引用上相對比較靈活,可以只引用部分測試片段或模塊內容。這樣一內一外不僅容易理解也容易記憶和學習。

    4.3.1實例

    (1)當Filename路徑的值為空,程序執行報錯,腳本執行中止,不會繼續執行下面的腳本內容。

    1、首先創建一個Filename路徑為空的測試計劃,如下圖所示:

    2、運行JMeter,查看結果樹(程序執行報錯,腳本執行中止,不會繼續執行下面 訪問博客園首頁 的取樣器),如下圖所示: 

    (2)當Filename路徑中的文件不存在,程序直接彈窗報錯並停止執行。

    1、首先創建一個Filename路徑中的文件不存在的測試計劃,點擊“保存”按鈕的時候,就會直接彈窗報錯。如下圖所示:

    (3)當Filename路徑的文件中不包含測試片段,跳過控制器,繼續向下執行。

    1、首先創建一個外部引用沒有測試片段的測試計劃,如下圖所示:

    2、創建一個Filename路徑的文件中不包含測試片段的測試計劃,將上邊的外部引用-無測試片段文件添加到Include控制器中,如下圖所示:

    3、運行JMeter,查看結果樹(跳過控制器,繼續向下執行 訪問博客園首頁 的取樣器),如下圖所示: 

    (3)當Filename路徑的文件中包含測試片段,執行完控制器,再繼續向下執行。

    1、首先創建一個外部引用有測試片段的測試計劃,如下圖所示:

    2、創建一個Filename路徑的文件中包含測試片段的測試計劃,將上邊的外部引用-有測試片段文件添加到Include控制器中,如下圖所示:

    3、運行JMeter,查看結果樹(執行完控制器里的測試片段,再繼續向下執行 訪問博客園首頁 的取樣器),如下圖所示: 

    到這裏,大家應該理解了  Include Controller 和  Test Fragment 了吧。宏哥的理解就是,Test Fragment 相當於一個獨立的部分,可以被其他測試計劃引用,實現 樣例的片段化,模塊化,遇到重複需要的,比如登錄、註冊之類的,就可以用Test FragmentInclude Controller 了。這樣可以避免重複造輪子,做許多無用功。

    5.小結

       好了,今天關於邏輯控制器的上篇就講解到這裏,這一篇主要介紹了 Critical Section ControllerForEach ControllerInclude控制器

     

    您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得隨手點波  推薦  不要忘記哦!!!

    別忘了點 推薦 留下您來過的痕迹

     

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

    【其他文章推薦】

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

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

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

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

    ※回頭車貨運收費標準

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

    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("結束環繞通知");
        }
    
    }
    

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

    【其他文章推薦】

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

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

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

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

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