最低5.48萬起,這些車代表了國產車最高水準?

相比較其它車企來說,寶駿就簡單粗暴多了,價格就是寶駿最大的優勢,因此寶駿也有價格屠夫的稱號,早期寶駿推出寶駿樂馳和寶駿630的時候其實價格優勢並不明顯,而從寶駿730和560開始,寶駿的高性價比稱號便越打越響,而310和510的上市也直接讓其坐穩了家轎市場的頭把交椅。

俗話說,沒有兩把刷子,怎麼能出來混社會;做人如此,造車也是這樣,對於各家車企來說,它們的產品雖然都各有優缺,但是那些賣的好混的不錯的車企卻往往有它們的看家本領。中國汽車品牌的繁榮發展雖然不過短短20年,但是卻也有不少的車企做得越來越大,在中國汽車市場上呼聲較高,除了自主車向來的高性價比之外,這些自主品牌都有什麼看家本領呢?

長安這些年來混得是順風順水,相當不錯;說起長安,可能很多人想到的是長安車型漂亮的外觀內飾,長安最新的睿騁CC和逸動就十分帥氣。

不過長安在自主車型中優勢最大的其實還是底盤,長安的車型底盤的厚實感和懸挂的濾震處理、側傾抑制都是相當出色的。長安的車型在底盤的質感上有一種歐系車的感覺,這是很多自主車型望塵莫及的。

代表車型:長安CS95

作為長安目前產品序列中最高級也是最碩大的車型,CS95代表了長安的產品高度,而實際上這款車的表現也是可圈可點,厚實的底盤不錯的隔音以及較高的性價比都是CS95的競爭力所在。

在自主車型中如果要問誰的發動機最好的話,那麼一定是榮威和MG的車型,目前榮威和MG產品序列中有兩款發動機堪稱強悍,那就是1.5T和2.0T的兩款渦輪增壓發動機,前者擁有169馬力/250牛米的動力,後者輸出更是高達220馬力/350牛米。

這樣的兩台發動機加持使得榮威MG的車型動力十分強悍,我們實測的1.5T名爵6百公里加速時間僅需7.09秒,可以說相當厲害了。除此之外搭載這兩台發動機的車型油耗也普遍比同規格的自主車型更低,實力可見一斑。

代表車型:名爵6

作為名爵榮威最有代表的車型,名爵6的動力十分強悍,1.5T的發動機加持下實測百公里加速僅需7.09秒,而且混合動力版本的名爵6加速還更加恐怖;除了強大的動力之外,名爵6在科技感上也相當出色,加上不錯的外觀,名爵6銷量也比較不錯了。

相比較其它車企來說,寶駿就簡單粗暴多了,價格就是寶駿最大的優勢,因此寶駿也有價格屠夫的稱號,早期寶駿推出寶駿樂馳和寶駿630的時候其實價格優勢並不明顯,而從寶駿730和560開始,寶駿的高性價比稱號便越打越響,而310和510的上市也直接讓其坐穩了家轎市場的頭把交椅。

寶駿的車型在保證品質的基礎上,價格卻總是比同規格的哈弗等車型便宜不少,因此也獲得了市場的熱捧,我們老闆就因為看中了寶駿的低價高質,買了台寶駿730給我們做公務用車呢~

代表車型:寶駿510

自從哈弗H6誕生以來,連續幾年的時間霸佔銷量榜首位,不過510發力之後完成了對哈弗H6的超越,憑藉超高的性價比以及靚麗的外觀,寶駿510為寶駿品牌的形象以及銷量立下了汗馬功勞,可以說510成就了如今的寶駿。

寶馬7系的遙控泊車可以說是一個創舉,但是第一個做遙控泊車的卻並非寶馬,而是咱們的比亞迪,並且比亞迪的遙控泊車不僅可以控制前後行駛,還能轉向,這就是比亞迪在科技配置上創新的體現,而諸如此類的电子配置很多,比如說全景影像、綠凈系統、可以自動切換內外循環的空調以及自帶記錄儀等功能都是比亞迪率先涉足的,在科技配置方面比亞迪說第二,傳統車企里估計沒人敢認第一。

代表車型:宋MAX

雖說宋MAX並非是比亞迪最高端的車型,但確實是比亞迪目前最受市場歡迎的車型了,除了那個漂亮的外觀和內飾之外,宋MAX的配置也是非常誇張,前後雷達、全景影像、電動尾門、前排座椅通風加熱、12.8英寸大屏、全LED大燈等配置出現在這麼一台十萬級的MpV也是十分誇張了。

從前有這麼一個段子,長城的老闆公布年度預算:“研發部門500萬,設計部門10億”,雖然是車友編出來的一個段子,但是也能看得出公眾對於長城車型的印象。而這一個設計花十億的印象也是直接來自於長城現有的車型。

在自主車型中長城的外觀內飾精緻度確實非常高,除了最近哈弗車系大面積推廣的电子手剎之外,在車輛的鈑金噴漆水平、內飾的用料做工甚至按鍵的手感質感上哈弗都在不遺餘力地做好,而這樣帶來的好處就是哈弗的車型與廉價感這一詞已經完全脫離關係了,無論是視覺感受還是觸感都十分出色,讓人愛不釋手。

代表車型:哈弗H7

目前哈弗產品中定位最高的並不是哈弗H7,但是在內飾外觀精緻度上認為哈弗H7是最出色的,尤其是擋桿後方的按鈕分佈,看起來用起來都有幾分奧迪的精緻感,加上車內不錯的做工用料,這個內飾的品質感絕對不輸30萬的合資車。

雖然長安車型的底盤質感不錯,但是長安為了迎合年輕人而做了很多運動化調校,因此多數長安車型的底盤濾振不算徹底,要說自主車型中哪個品牌的車濾振最能給人好感,虎哥覺得一定是東南。

東南車型雖然外觀足夠靚麗,但是並非是普通貨色,在濾振水平上東南可謂相當出色,比如說東南DX3和東南DX7的濾振就足夠徹底,路面上大大小小的振動都能被過濾得十分到位,即使是快速軋過井蓋也不會有單薄感和突兀感,感覺有一種貼地飛行的質感,濾振水平完全不遜色於別克。

代表車型:東南DX3

在試駕DX3就對DX3的濾震水平十分震驚,激烈駕駛時底盤的安穩感很好、經過大大小小的坑窪時車內感覺都相當淡定,懸挂的濾振表現值得表揚,底盤的厚實感也是比較到位了,超過同價位的多數自主車。

2010年前後,中國市場掀起了一股合資自主品牌的風潮,當時許多諸如理念、啟辰、朗世之類的合資自主品牌誕生,但是大潮褪去才知道誰在裸泳,如今完整活下來並且混得還不錯的也就剩下啟辰了。

而說起啟辰最厲害的地方,那就是啟辰的車型基本就是換殼的日產,比如說T70實際上就是海外的7座版老款逍客、D60就是軒逸、D50/R50也就是老款的日產騏達,因此在三大件和造車水準上啟辰也原封不動地繼承了日產的基因,但是在價格上啟辰比哈弗之類的自主車有過之而無不及,因此賣得好也不足為奇了。

代表車型:啟辰T70

啟辰T70實際上就是海外7座版逍客的底盤,加上日產那套成熟的2.0L+CVT動力總成,雖然動力不算強悍,但是勝在可靠性和燃油經濟性好,這也是選擇啟辰的一大重要原因,在性價比上T70也超過了大多數的自主車,比如說11.78萬的T70 2.0L CVT睿享版就有定速巡航、胎壓監測、一鍵啟動無鑰匙進入、主駕駛電動座椅等高端裝備。

有神似奧迪Q3的SR7、跟保時捷macan傻傻分不清的SR9、撞臉大眾概念SUV的大邁X7、有奧迪A6L內涵的眾泰Z700以及神似奧迪Q5的眾泰T600,花五分之一的錢買一輛豪車,誰能不心動?

代表車型:幾乎全系車型~本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

復聯3上映的深夜,一群男人卻鑽進地庫嗨翻了天

對於性能向改裝玩家來說,不管平時駕駛時到底會不會時刻關注如此豐富的數據,像這樣的三聯表是必須裝上的。十代思域顯然也是如今性能向改裝的主力車型,1。5T渦輪增壓發動機有着相當不錯的改裝潛力。“網紅車”五菱宏光現身。

相信大部分車迷都會對改裝車感興趣,甚至自己本身就是一位改裝車玩家,而對於廣大改裝車愛好者來說,靜態車聚就是一種讓大家能夠零距離接觸各類改裝案例,同時大量車友交流改裝心得的活動之一。很多改裝團體會選擇地下停車場這種封閉性公共場所作為大型改裝車聚的舉辦地,而在廣州,卻從未有過此類車聚。日前,趁着熱度極高的漫威電影《復讎者聯盟3》的國內上映,一個名為Aibo par的“地庫車聚”在廣州某商場舉行,自己作為一個車迷,筆者當然不會錯過這場被稱為“廣州首次”的地庫車聚。

與珠三角地區常見的賽道日活動相比,地庫車聚更多的還是驚喜改裝車的靜態展示,因此在這裏集結的改裝車大多以外觀、內飾改裝為核心,每一台改裝車都显示出鮮明的個性。

低姿態

“姿態”,這是外觀向改裝一個非常常用的詞語,是一台車改裝水平的重要評定標準,而所謂姿態,涉及到離地間隙、車輪傾角、輪轂選擇等多個方面,但在國內的改裝愛好者群體中,“低趴”就是最受歡迎的改裝風格之一。

就在會場簽到處,主辦方就擺出了兩台霸氣的VIp風格改裝作品,巨大的傾角、嵌入翼子板的大尺寸輪轂,讓這台奔馳S級和豐田皇冠看起來霸氣十足。

豐田皇冠是國內的VIp風格主流改裝用車,其中以第12代皇冠最為常見。

除了多基於中大型甚至大型轎車的VIp風格之外,在這裏還要提到一個改裝風格的專用名詞:“Hella Flush”。這種非常流行的外觀改裝風格要求輪轂邊緣與輪眉平齊,大部分玩家會選擇換裝氣動避震來實現最大幅度降低車身的效果,而在行駛時又可將離地間隙提升,保證一定的實用性。

克萊斯勒300C是國內難得的純種美式轎車,粗獷的線條搭配巨大的鍍鉻輪轂,盡顯美式風範。

什麼?國內竟有豐田bB?淡定,這是被改造成豐田bB外觀的長城酷熊。

外觀向改裝玩家可不只是會對外觀進行改造,他們還會用一些小物件來裝飾愛車的內部,模型車、玩偶、汽車主題貼紙等各式各樣的裝飾物看得筆者眼花繚亂。

這位車主直接將自己的酷熊打造成了移動的日式工藝品專賣店。

由於靜態車聚中常會有車友打開前蓋展示精心改造的發動機艙,為了讓愛車美得更全面,發動機蓋的背面也是不能放過的。

對於趴地玩家來說,前後包圍被蹭壞甚至掉落是一項必修課程,包圍還沒掉下來?用黃黑膠布貼上“假裝”掉了也可以。

“鑽桿”是低趴改裝玩家在車聚中最喜愛的活動,車友們設法降低車身離地高度,開車鑽過一根限定高度的杆子,以評比出車身最低的車型。

既然是漫威電影的首映車聚,怎能少得了鋼鐵俠的身影?

猜猜這台有着哆啦A夢塗裝的是什麼車?記得在下方留言框把你猜到的答案告訴我們哦!

性能派

當然,雖說靜態車聚是外觀向改裝的主場主場,但這不代表性能派就不能出現了。

豐田86顯然是最受歡迎的日系跑車之一,也是各類賽道日活動的常見車型;只可惜這款超級實惠的后驅小跑車如今已經退出中國內地市場了。

素有“平民超跑”之稱的飛度GK5,是改裝界最火爆的車型之一,能夠駕馭從低趴到性能的多種改裝風格。

比亞迪F0被降低車身,換上競技輪轂之後,突然有了一種性能小鋼炮的感覺。

這台狀態上佳的第八代STI是全場性能車的焦點之一。

對於性能向改裝玩家來說,不管平時駕駛時到底會不會時刻關注如此豐富的數據,像這樣的三聯表是必須裝上的。

十代思域顯然也是如今性能向改裝的主力車型,1.5T渦輪增壓發動機有着相當不錯的改裝潛力。

“網紅車”五菱宏光現身!

這個巨大的碳纖維進氣風箱是必須秀出來的。

市售兩千多元的電動渦輪增壓器,它的增壓值能有0.1個Bar么?

本田高性能圖騰思域Type R一現身,大批車友上前圍觀拍照,這人氣,恐怕是法拉利的旗艦跑車都無法比擬。

經典派

現場還能見到許多經典車的身影,比如近年流行起來的桑塔納,以及老皇冠、虎頭奔、Spura等車型都看得筆者口水直流。

近年老款桑塔納在國內再次流行起來,這次車聚就出現了不少桑塔納的身影。

曾幾何時,斯巴魯在中國和貴州雲雀合作,以合資生產的方式推出了雲雀小公主,也就是斯巴魯Vivio;而圖中這台可不是國內最常見的雲雀小公主,而是一台正兒八經的斯巴魯Vivio!

W140“虎頭奔”登場,哪怕這隻是一台S320,但是氣場也是足夠強大的。

斯巴魯Vivio的Bistro版本,而這台則是非常少見的雙門車型。

喲!豐田Supra出租車!請問起步價多少?

寶馬推出的第二款Z系列跑車:Z3。

這台皇冠155的車主看來頗有美國情懷啊,但是這樣的國旗搭配,不應該用在經典的紅旗或者林肯、凱迪拉克身上嗎?

豐田在90年代推出的緊湊型轎車Altezza,在國內以雷克薩斯第一代IS的身份銷售,但國內車主更願意用它的日本名字:Altezza,或者親切地叫它“咬地鯊”。

大跑車

在這一次地庫車聚中,吸引眼球的可不止是那些低姿態、性能車和經典車,現場更有大批跑車現身,對於車迷來說,這些又帥又快的高性能跑車就是心中的Dream Cars。

國內罕見的阿爾法羅密歐4C!也許很快大家就能在玩車TV的推送里見到它哦!

保時捷911 GT3 RS,只可惜國內已買不到手動變速箱版本。

法拉利,作為世界超級跑車標杆的地位也阻止不了車主給它換上氣動避震,玩起了姿態。

氣動避震的儲氣罐就隱藏在車頭的狹小行李箱中。

結語

這場看似簡單的地庫車聚,當晚共吸引了數百台改裝車前來參与,用盡了活動區域的每一個車位;地庫的悶熱和難以消散的廢氣都無法阻擋改裝車愛好者的熱情。拋開電影上映這個活動主題不說,實際上絕大部分前來參与車聚的人都是被改裝車本身所吸引,能夠讓過千人在一個擁擠的地下停車場玩得如此盡興,也許就只有改裝車聚這一種活動能夠做到了。

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

【其他文章推薦】

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

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

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

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

8萬就夠,近期最多人關注的3款6座車都這麼給力,買誰好?

而寶駿360第三排的空間表現不錯,美中不足的是其坐墊對於大腿的承托稍顯不足。比亞迪宋MAX 6座版表現要比7座版本更為靈活和更為寬鬆,不管前排、中排還是後排都能夠找到舒適輕鬆的坐姿。扒一扒內飾寶駿360:中控檯布局與寶駿510相似,整體內飾層次感較為豐富,配合懸浮式中控屏以及液晶儀錶盤,整個內飾顯得科技感十足。

什麼車廠最了解國內消費者的需要?答案必定是本土車廠。想必大家也知道2018車輛年檢時間有新規定,非營運轎車享有6年內免上線檢測政策,可尷尬的是現在許多MpV車型是7座的布局,因此許多MpV被迫要一年一檢。對此本土車廠紛紛為消費者排憂解難,相繼推出了6座MpV車型,讓新車可以滿足新規從而6年內免上線檢測。接下來我們看看最近新上市的3款6座MpV吧。

寶駿作為一個善於打造爆款車型的品牌,不僅能打造出高性價比的車型,更重要的是它清晰當今消費者需求,上周剛推出了旗下第二款MpV車型——寶駿360,該車瞄準的就是6座MpV這一細分市場。

全新的歐尚A600是長安繼歐尚A800后又一力作,從命名來看,其定位是在A800之下。從外觀跟內飾看,歐尚A600可作為歐尚的升級改款。相比於原本的歐尚,多了一種動力組成,也多了自動擋車型的選擇,這樣的變化讓歐尚A600更加的親民。

作為爆款車型的比亞迪宋MAX也推出了六座車型,可見比亞迪對於六座MpV這一細分市場的重視程度。新車在尺寸上保持與7座車型一致,減少了一個座位,換來的是更寬敞的中排空間以及能更方便進出第三排的中央通道。

比一比尺寸

通過三車尺寸數據的對比可以看出比亞迪宋MAX佔據一定的優勢,尤其是在軸距以及寬度方面。由此可以推斷出比亞迪宋MAX的車內空間表現應為三車之最。寶駿360在尺寸上比歐尚A600稍微大一些,可是軸距上的差距是明顯的,其軸距已貼近宋MAX,換句話說寶駿360在車廂內的空間不比宋MAX差太多。

經過實測也驗證了前文的觀點,可以看到,三台車前排空間是足夠寬敞。受限於軸距,長安歐尚A600在第二排以及第三排在腿部空間上稍顯局促,應付日常短途出行問題不大。而寶駿360第三排的空間表現不錯,美中不足的是其坐墊對於大腿的承托稍顯不足。比亞迪宋MAX 6座版表現要比7座版本更為靈活和更為寬鬆,不管前排、中排還是後排都能夠找到舒適輕鬆的坐姿。

扒一扒內飾

寶駿360:中控檯布局與寶駿510相似,整體內飾層次感較為豐富,配合懸浮式中控屏以及液晶儀錶盤,整個內飾顯得科技感十足。

長安歐尚A600:內飾與歐尚相似,連貫式儀錶和中控台是一討喜的設計,細節部分歐尚A600與歐尚有着細微的差別,比如空調出風口飾板的微調以及空調控制區域按鈕的布局,這些微調使歐尚A600較於歐尚更為精緻。

比亞迪宋MAX:6座版本內飾布局與7座完全一致,在內飾的配色上新增了黑+棕色的版本,使整個內飾看上去不再沉悶。

瞧一瞧動力

動力方面,寶駿360搭載與寶駿310系列相同的1.5L自然吸氣發動機,最大輸出功率82kW,和發動機相匹配是6速手動和自動擋。長安歐尚A600動力配置上較為豐富,提供了1.5L和1.6L兩種動力選擇,此外,新車在1.6L車型上均匹配了六速自動變速箱,從而提高了車型的競爭力。比亞迪宋MAX則是熟悉的1.5T渦輪增壓發動機匹配6速手動變速箱或6速雙離合變速箱。

總結:以上三台車都是本土車廠為滿足國內消費者需要而交出的答卷。可以看出歐尚A600與寶駿360均走高性價比路線,歐尚A600自動變速箱是其一個優勢,同樣的價格區間內寶駿360有空間的優勢。相比之下,比亞迪宋MAX6座版整體配置是跟7座版本看齊,更多的可以將其看作為順應新政策而在座椅數上作出的妥協,不過也因為少了一個座,車內的空間表現將比7座版本更好。以上就是最近新上市的三款六座MpV至於要怎麼選,相信各位心中自有答案。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※超省錢租車方案

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

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

淑女?劈蕉佬?這些雷人車型名字你了解幾個?

有誰想到這款車當年竟然是名棄嬰,四處找人收留。Jimny的型號的原本來自一間叫希望汽車的生產廠家,該公司研製了一部希望之星ON360,但鑒於公司規模,老闆小野定良計劃向三菱汽車推銷代工制權,但三菱礙於希望汽車的往績,並沒有接受這單生意,最後只能硬着頭皮自行生產,並於1967年底上市,可惜銷量不如預期。

每部車都有着自己的型號名,一般來說就是字母加数字的組合,或單純以文字作為型號名,在當中有的更隱藏別具意義的故事,今天就和大家分享幾個有趣的故事。

淑女的由來

“惡魔Z”、“大魔王”這些都是我們對Fairlady的尊稱,日產經典跑車系列Fairlady這個名字的靈感來源於百老匯歌舞劇My Fair Lady, 1961年時任社長川又克二正在美國公幹,機緣巧合下觀看了這套長壽歌舞劇,同期美國即將推出新款跑車SLp213,一下子就決定新車冠以Fairlady之名,希望它像該歌劇一樣受歡迎,並成為經典。

380萬中挑一

Sunny(陽光)於1966年推出,曾經是日產主力家庭用車,當年日產在報紙廣告上預告推出一升的新車,並進行募集車名活動,在緊接一輪廣告攻勢逐步發布新車細節后,接連一個月宣傳吸引了848萬人參與,收到共380萬個名字推薦,最後選定了切合車型概念的Sunny為名。

南美洲“劈蕉佬”

不少越野發燒友及工程人員鍾情的三菱pajero(帕傑羅),因其英文發音和粵語里的“劈蕉佬”有着99%的相似度,瞬間顯得親民又剛強。至於pajero名稱的起源,則是取自於生活在阿根廷南部高原地帶的一種山貓,它活躍於崎嶇山間,正好吻合pajero的強勁野外走破性能,更讓這隻猛獸衝出南美洲,穿梭於全球各地山野。

人棄我取,終成經典

硬派越野車一直給人一種高大上的感覺,但也有例外,鈴木Jimny(吉姆尼)就是這樣一款小巧見稱的越野車,即使到了今天仍然是不少越野愛好者的寵兒。有誰想到這款車當年竟然是名棄嬰,四處找人收留。Jimny的型號的原本來自一間叫希望汽車的生產廠家,該公司研製了一部希望之星ON360,但鑒於公司規模,老闆小野定良計劃向三菱汽車推銷代工制權,但三菱礙於希望汽車的往績,並沒有接受這單生意,最後只能硬着頭皮自行生產,並於1967年底上市,可惜銷量不如預期。於是小野定良改去向鈴木汽車負責人鈴木修推銷此車,鈴木修對此車一見鍾情,即使公司上下都反對仍堅持一己之見,最終以1,200萬日元向希望汽車買斷整個設計,並於1970年4月推出初代Jimny,造就這部鈴木的招牌車款。

買回來的名字

在Integra未面世之前,prelude(廣東及港澳地區稱“披露”)就是本田coupe車款的代表,也是展現本田各種黑科技的試驗田。DOHC VTEC、雙搖臂懸架及四輪轉向系統等配置早早就出現在prelude之上,中文意謂“前奏曲”的prelude名字原為豐田擁有,當本田於70年代末期決定以此為新車型號后才發現早已被豐田註冊了名字。本來最簡單的方法就是改名,但當年本田執意鍾情於prelude這個名字,於是主動向豐田提出轉讓要求,結果一輪商議后prelude終於歸入本田名下。雖然雙方未有提到當中細節,不過相信離不開用金錢來解決,而這個買回來的名字就一直使用到2001年第五代prelude停產為止,歷時23年。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

近5米長,舒適度同級無敵,這款18.99萬起的車值不值?

雪鐵龍C6上配備的1。8T發動機是pSA集團在中國最高階的發動機。這台發動機的賬面數據和實際表現當然比不上對手最高階的發動機,但是比起他們中階發動機,倒也不至於落後。傳動系統是來自愛信的6AT變速箱,這台變速箱可以說拖了後腿,競爭對手大多數用上了8、9AT或者7速雙離合的產品。

在2008年,C6曾經以中大型車的身份引進中國。當時的雪鐵龍C6是C級車的身份,售價高達64萬。時過境遷,當C6再次回到國人視線里時,已經是B級車的身份,而且售價也僅需18.99-27.99萬。

這一代的C6是一款中國特供車型,專為國人設計。中國人喜歡的元素,超大後排空間、肉眼可見的豪華感、豐富高端的配置、運動流暢的車身造型,在這台C6上一樣不缺。然而,C6的銷量非常慘淡。好在,今天我的任務不是解答為什麼C6銷量慘淡,而是要告訴你這台車到底有多棒。

雪鐵龍C6的外觀以沉穩為主,前臉的雪鐵龍雙人標識延伸到整個車頭,車頭的線條以水平為主,搭配上大面積的鍍鉻格柵,鑽晶型日間行車燈,彰顯了C6行政級轎車的定位。尾部造型飽滿,銀色的鍍鉻裝飾條連接了兩旁的回字形尾燈,盡顯格調。C6側麵線條流暢動感,缺少了一絲行政級轎車應有的厚重感,而且影響了頭部空間的表現。

雪鐵龍C6的車身尺寸比市面上大多數B級車都要大,甚至可以列入C級車的行列。

上帝在製造法國人的時候,只給了他們優秀的設計能力,卻沒有把將設計付諸現實的能力一併安裝上去。C6車身漆面左右厚薄不一,而且這款白色車漆容易沾灰且難以清潔。

雪鐵龍C6的內飾比外觀做得還好。C6的內飾採用了最新家族式對稱式設計,造型設計更加註重檔次感。材質方面啊,C6的內飾採用了大量的Nappa真皮,實木飾板,同級再也找不到更好的。全液晶儀錶盤的显示效果清晰,可調節的選項豐富,UI設計出色。

C6座椅方面採用了Nappa真皮包裹,座椅寬大,填充物支撐性足。這台C6的頂配車型,前後座椅均有座椅通風/加熱/按摩功能,這種級別的配置也是同級所不具備的。

C6的乘坐空間只有一個字——大。1米73的乘客在前排調好位置后,在後排能夠獲得3拳2指左右的腿部空間。可惜,受流線型車身的影響,頭部空間不容樂觀,前排和後排分別只有3指和4指的表現。

C6的後備廂空間非常大,有523L的容積。不過後排座椅不能放倒,所以沒有擴充的空間。

雪鐵龍C6上配備的1.8T發動機是pSA集團在中國最高階的發動機。這台發動機的賬面數據和實際表現當然比不上對手最高階的發動機,但是比起他們中階發動機,倒也不至於落後。傳動系統是來自愛信的6AT變速箱,這台變速箱可以說拖了後腿,競爭對手大多數用上了8、9AT或者7速雙離合的產品。這款6AT的擋位數就顯得落後了。從匹配上來說,整套動力系統也不夠線性,起步時需要很小心地控制油門才不會突然被“踢”一腳。如果C6能來個ECO模式,相信會好很多。

雪鐵龍C6的0-100km/h實測百公里加速時間為9.4秒。當天有小雨,地面略微有積水,但是加速的過程245mm寬的輪胎幾乎沒有打滑,很平順地就衝出去了。這數據雖然不能跟競爭對手的高階動力系統對比,但是跟他們的1.5T或1.8T的動力對比,還是有競爭力的。

既然雪鐵龍C6作為一款行政級定位的轎車,底盤肯定是以舒適為主的。雪鐵龍C6的減振器和避震彈簧採用斜置的布置方式,而且減振器和避震彈簧另一端連接的是副車架,而不是車身。這麼做的好處,就是減少減振器上垂直方向的力和避免力直接作用於車身,最終達到乘坐舒適的效果。實際體驗下來,雪鐵龍C6確實能很好地將路面顛簸過濾掉,比起同級對手單薄的濾震能力要好上不少,甚至可以說,這是C級車上會有的濾震能力。

雪鐵龍C6的方向盤採用電動液壓助力,路感非常清晰,沒有什麼虛位,回正的力度也線性,只是手感比較重,更加適合男性駕駛。

C6的隔音水平也是行政級水準的。C6四門車窗都使用了雙層隔音玻璃。C6在怠速時幾乎聽不到發動機的聲音,高速跑起來的時候輪胎噪音會相對較大,而風噪不明顯。

從市場定位上來說,與C6有相似定位的B級車,只有別克君越這一款。他們都有舒適的底盤表現,寬敞的乘坐空間,高檔的內飾氛圍。兩款拿出來比較,C6的配置更高,後期保養更便宜,而君越的動力會更完善。如果不考慮品牌知名度,C6會更加合適。當然,如果雪鐵龍的品牌知名度能夠打出來,C6肯定不會是現在這個定價。所以,各位觀眾朋友,要撿便宜趁現在了。

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧

[源碼解析] GroupReduce,GroupCombine 和 Flink SQL group by

[源碼解析] GroupReduce,GroupCombine和Flink SQL group by

目錄

  • [源碼解析] GroupReduce,GroupCombine和Flink SQL group by
    • 0x00 摘要
    • 0x01 緣由
    • 0x02 概念
      • 2.1 GroupReduce
      • 2.2 GroupCombine
      • 2.3 例子
    • 0x03 代碼
    • 0x04 Flink SQL內部翻譯
    • 0x05 JobGraph
    • 0x06 Runtime
      • 6.1 ChainedFlatMapDriver
      • 6.2 GroupReduceCombineDriver
      • 6.3 GroupReduceDriver & ChainedFlatMapDriver
    • 0x07 總結
    • 0x08 參考

0x00 摘要

本文從源碼和實例入手,為大家解析 Flink 中 GroupReduce 和 GroupCombine 的用途。也涉及到了 Flink SQL group by 的內部實現。

0x01 緣由

在前文[源碼解析] Flink的Groupby和reduce究竟做了什麼中,我們剖析了Group和reduce都做了些什麼,也對combine有了一些了解。但是總感覺意猶未盡,因為在Flink還提出了若干新算子,比如GroupReduce和GroupCombine。這幾個算子不搞定,總覺得如鯁在喉,但沒有找到一個良好的例子來進行剖析說明。

本文是筆者在探究Flink SQL UDF問題的一個副產品。起初是為了調試一段sql代碼,結果發現Flink本身給出了一個GroupReduce和GroupCombine使用的完美例子。於是就拿出來和大家共享,一起分析看看究竟如何使用這兩個算子。

請注意:這個例子是Flink SQL,所以本文中將涉及Flink SQL goup by內部實現的知識。

0x02 概念

Flink官方對於這兩個算子的使用說明如下:

2.1 GroupReduce

GroupReduce算子應用在一個已經分組了的DataSet上,其會對每個分組都調用到用戶定義的group-reduce函數。它與Reduce的區別在於用戶定義的函數會立即獲得整個組。

Flink將在組的所有元素上使用Iterable調用用戶自定義函數,並且可以返回任意數量的結果元素。

2.2 GroupCombine

GroupCombine轉換是可組合GroupReduceFunction中組合步驟的通用形式。它在某種意義上被概括為允許將輸入類型 I 組合到任意輸出類型O。與此相對的是,GroupReduce中的組合步驟僅允許從輸入類型 I 到輸出類型 I 的組合。這是因為GroupReduceFunction的 “reduce步驟” 期望自己的輸入類型為 I。

在一些應用中,我們期望在執行附加變換(例如,減小數據大小)之前將DataSet組合成中間格式。這可以通過CombineGroup轉換能以非常低的成本實現。

注意:分組數據集上的GroupCombine在內存中使用貪婪策略執行,該策略可能不會一次處理所有數據,而是以多個步驟處理。它也可以在各個分區上執行,而無需像GroupReduce轉換那樣進行數據交換。這可能會導致輸出的是部分結果,所以GroupCombine是不能替代GroupReduce操作的,儘管它們的操作內容可能看起來都一樣。

2.3 例子

是不是有點暈?還是直接讓代碼來說話吧。以下官方示例演示了如何將CombineGroup和GroupReduce轉換用於WordCount實現。即通過combine操作先對單詞數目進行初步排序,然後通過reduceGroup對combine產生的結果進行最終排序。因為combine進行了初步排序,所以在算子之間傳輸的數據量就少多了

DataSet<String> input = [..] // The words received as input

// 這裏通過combine操作先對單詞數目進行初步排序,其優勢在於用戶定義的combine函數只調用一次,因為runtime已經把輸入數據一次性都提供給了自定義函數。  
DataSet<Tuple2<String, Integer>> combinedWords = input
  .groupBy(0) // group identical words
  .combineGroup(new GroupCombineFunction<String, Tuple2<String, Integer>() {

    public void combine(Iterable<String> words, Collector<Tuple2<String, Integer>>) { // combine
        String key = null;
        int count = 0;

        for (String word : words) {
            key = word;
            count++;
        }
        // emit tuple with word and count
        out.collect(new Tuple2(key, count));
    }
});

// 這裏對combine的結果進行第二次排序,其優勢在於用戶定義的reduce函數只調用一次,因為runtime已經把輸入數據一次性都提供給了自定義函數。  
DataSet<Tuple2<String, Integer>> output = combinedWords
  .groupBy(0)                              // group by words again
  .reduceGroup(new GroupReduceFunction() { // group reduce with full data exchange

    public void reduce(Iterable<Tuple2<String, Integer>>, Collector<Tuple2<String, Integer>>) {
        String key = null;
        int count = 0;

        for (Tuple2<String, Integer> word : words) {
            key = word;
            count++;
        }
        // emit tuple with word and count
        out.collect(new Tuple2(key, count));
    }
});

看到這裏,有的兄弟已經明白了,這和mapPartition很類似啊,都是runtime做了大量工作。為了讓大家這兩個算子的使用情形有深刻的認識,我們再通過一個sql的例子,向大家展示Flink內部是怎麼應用這兩個算子的,也能看出來他們的強大之處

0x03 代碼

下面代碼主要參考自 flink 使用問題匯總。我們可以看到這裏通過groupby進行了聚合操作。其中collect方法,類似於mysql的group_concat。

public class UdfExample {
    public static class MapToString extends ScalarFunction {

        public String eval(Map<String, Integer> map) {
            if(map==null || map.size()==0) {
                return "";
            }
            StringBuffer sb=new StringBuffer();
            for(Map.Entry<String, Integer> entity : map.entrySet()) {
                sb.append(entity.getKey()+",");
            }
            String result=sb.toString();
            return result.substring(0, result.length()-1);
        }
    }

    public static void main(String[] args) throws Exception {
        MemSourceBatchOp src = new MemSourceBatchOp(new Object[][]{
                new Object[]{"1", "a", 1L},
                new Object[]{"2", "b33", 2L},
                new Object[]{"2", "CCC", 2L},
                new Object[]{"2", "xyz", 2L},
                new Object[]{"1", "u", 1L}
        }, new String[]{"f0", "f1", "f2"});

        BatchTableEnvironment environment = MLEnvironmentFactory.getDefault().getBatchTableEnvironment();
        Table table = environment.fromDataSet(src.getDataSet());
        environment.registerTable("myTable", table);
        BatchOperator.registerFunction("MapToString",  new MapToString());
        BatchOperator.sqlQuery("select f0, mapToString(collect(f1)) as type from myTable group by f0").print();
    }
}

程序輸出是

f0|type
--|----
1|a,u
2|CCC,b33,xyz

0x04 Flink SQL內部翻譯

這個SQL語句的重點是group by。這個是程序猿經常使用的操作。但是大家有沒有想過這個group by在真實運行起來時候是怎麼操作的呢?針對大數據環境有沒有做了什麼優化呢?其實,Flink正是使用了GroupReduce和GroupCombine來實現並且優化了group by的功能。優化之處在於:

  • GroupReduce和GroupCombine的函數調用次數要遠低於正常的reduce算子,如果reduce操作中涉及到頻繁創建額外的對象或者外部資源操作,則會相當省時間。
  • 因為combine進行了初步排序,所以在算子之間傳輸的數據量就少多了。

SQL生成Flink的過程十分錯綜複雜,所以我們只能找最關鍵處。其是在 DataSetAggregate.translateToPlan 完成的。我們可以看到,對於SQL語句 “select f0, mapToString(collect(f1)) as type from myTable group by f0”,Flink系統把它翻譯成如下階段,即

  • pre-aggregation :排序 + combine;
  • final aggregation :排序 + reduce;

從之前的文章我們可以知道,groupBy這個其實不是一個算子,它只是排序過程中的一個輔助步驟而已,所以我們重點還是要看combineGroup和reduceGroup。這恰恰是我們想要的完美例子。

input ----> (groupBy + combineGroup) ----> (groupBy + reduceGroup) ----> output

SQL生成的Scala代碼如下,其中 combineGroup在後續中將生成GroupCombineOperator,reduceGroup將生成GroupReduceOperator。

  override def translateToPlan(
      tableEnv: BatchTableEnvImpl,
      queryConfig: BatchQueryConfig): DataSet[Row] = {

    if (grouping.length > 0) {
      // grouped aggregation
      ...... 
      if (preAgg.isDefined) { // 我們的例子是在這裏
        inputDS          
          // pre-aggregation
          .groupBy(grouping: _*)
          .combineGroup(preAgg.get) // 將生成GroupCombineOperator算子
          .returns(preAggType.get)
          .name(aggOpName)
          // final aggregation
          .groupBy(grouping.indices: _*) //將生成GroupReduceOperator算子。
          .reduceGroup(finalAgg.right.get)
          .returns(rowTypeInfo)
          .name(aggOpName)
      } else {
        ......
      }
    }
    else {
      ......
    }
  }
}

// 程序變量打印如下
this = {DataSetAggregate@5207} "Aggregate(groupBy: (f0), select: (f0, COLLECT(f1) AS $f1))"
 cluster = {RelOptCluster@5220} 

0x05 JobGraph

LocalExecutor.execute中會生成JobGraph。JobGraph是提交給 JobManager 的數據結構,是唯一被Flink的數據流引擎所識別的表述作業的數據結構,也正是這一共同的抽象體現了流處理和批處理在運行時的統一。

在生成JobGraph時候,系統得到如下JobVertex。

jobGraph = {JobGraph@5652} "JobGraph(jobId: 6aae8b5e5ad32f588136bef26f8b65f6)"
 taskVertices = {LinkedHashMap@5655}  size = 4

{JobVertexID@5677} "c625209bb7fb9a098807551840aeaa99" -> {InputOutputFormatVertex@5678} "CHAIN DataSource (at initializeDataSource(MemSourceBatchOp.java:98) (org.apache.flink.api.java.io.CollectionInputFormat)) -> FlatMap (select: (f0, f1)) (org.apache.flink.runtime.operators.DataSourceTask)"

{JobVertexID@5679} "b56ace4acd7a2f69ea110a9f262ff80a" -> {JobVertex@5680} "CHAIN GroupReduce (groupBy: (f0), select: (f0, COLLECT(f1) AS $f1)) -> FlatMap (select: (f0, mapToString($f1) AS type)) -> Map (Map at linkFrom(MapBatchOp.java:35)) (org.apache.flink.runtime.operators.BatchTask)"
 
{JobVertexID@5681} "3f5e2a0f700421d80ce85e02a6d9db73" -> {InputOutputFormatVertex@5682} "DataSink (collect()) (org.apache.flink.runtime.operators.DataSinkTask)"
 
{JobVertexID@5683} "ad29dc5b2e0a39ad2cd1d164b6f859f7" -> {JobVertex@5684} "GroupCombine (groupBy: (f0), select: (f0, COLLECT(f1) AS $f1)) (org.apache.flink.runtime.operators.BatchTask)"

我們可以看到,在JobGraph中就生成了對應的兩個算子。其中這裏的FlatMap就是用戶的UDF函數MapToString的映射生成。

GroupCombine (groupBy: (f0), select: (f0, COLLECT(f1) AS $f1))  
  
CHAIN GroupReduce (groupBy: (f0), select: (f0, COLLECT(f1) AS $f1)) -> FlatMap (select: (f0, mapToString($f1) AS type)) -> Map 

0x06 Runtime

最後,讓我們看看runtime會如何處理這兩個算子。

6.1 ChainedFlatMapDriver

首先,Flink會在ChainedFlatMapDriver.collect中對record進行處理,這是從Table中提取數據所必須經歷的,與後續的group by關係不大。

@Override
public void collect(IT record) {
   try {
      this.numRecordsIn.inc();
      this.mapper.flatMap(record, this.outputCollector);
   } catch (Exception ex) {
      throw new ExceptionInChainedStubException(this.taskName, ex);
   }
}

// 這裡能夠看出來,我們獲取了第一列記錄
record = {Row@9317} "1,a,1"
 fields = {Object[3]@9330} 
this.taskName = "FlatMap (select: (f0, f1))"

// 程序堆棧打印如下
collect:80, ChainedFlatMapDriver (org.apache.flink.runtime.operators.chaining)
collect:35, CountingCollector (org.apache.flink.runtime.operators.util.metrics)
invoke:196, DataSourceTask (org.apache.flink.runtime.operators)
doRun:707, Task (org.apache.flink.runtime.taskmanager)
run:532, Task (org.apache.flink.runtime.taskmanager)
run:748, Thread (java.lang)

6.2 GroupReduceCombineDriver

其次,GroupReduceCombineDriver.run()中會進行combine操作。

  1. 會通過this.sorter.write(value)把數據寫到排序緩衝區。
  2. 會通過sortAndCombineAndRetryWrite(value)進行實際的排序,合併。

因為是系統實現,所以Combine的用戶自定義函數就是由Table API提供的,比如org.apache.flink.table.functions.aggfunctions.CollectAccumulator.accumulate

@Override
public void run() throws Exception {
   final MutableObjectIterator<IN> in = this.taskContext.getInput(0);
   final TypeSerializer<IN> serializer = this.serializer;

   if (objectReuseEnabled) {
    .....
   }
   else {
      IN value;
      while (running && (value = in.next()) != null) {
         // try writing to the sorter first
         if (this.sorter.write(value)) {
            continue;
         }

         // do the actual sorting, combining, and data writing
         sortAndCombineAndRetryWrite(value);
      }
   }

   // sort, combine, and send the final batch
   if (running) {
      sortAndCombine();
   }
}

// 程序變量如下
value = {Row@9494} "1,a"
 fields = {Object[2]@9503} 

sortAndCombine是具體排序/合併的過程。

  1. 排序是通過 org.apache.flink.runtime.operators.sort.QuickSort 完成的。
  2. 合併是通過 org.apache.flink.table.functions.aggfunctions.CollectAccumulator.accumulate 完成的。
  3. 給下游是由 org.apache.flink.table.runtime.aggregate.DataSetPreAggFunction.combine 調用 out.collect(output) 完成的。
private void sortAndCombine() throws Exception {
   final InMemorySorter<IN> sorter = this.sorter;
   // 這裏進行實際的排序
   this.sortAlgo.sort(sorter);
   final GroupCombineFunction<IN, OUT> combiner = this.combiner;
   final Collector<OUT> output = this.output;

   // iterate over key groups
   if (objectReuseEnabled) {
			......		
   } else {
      final NonReusingKeyGroupedIterator<IN> keyIter = 
            new NonReusingKeyGroupedIterator<IN>(sorter.getIterator(), this.groupingComparator);
      // 這裡是歸併操作
      while (this.running && keyIter.nextKey()) {
         // combiner.combiner 是用戶定義操作,runtime把某key對應的數據一次性傳給它
         combiner.combine(keyIter.getValues(), output);
      }
   }
}

具體調用棧如下:

accumulate:57, CollectAggFunction (org.apache.flink.table.functions.aggfunctions)
accumulate:-1, DataSetAggregatePrepareMapHelper$5
combine:71, DataSetPreAggFunction (org.apache.flink.table.runtime.aggregate)
sortAndCombine:213, GroupReduceCombineDriver (org.apache.flink.runtime.operators)
run:188, GroupReduceCombineDriver (org.apache.flink.runtime.operators)
run:504, BatchTask (org.apache.flink.runtime.operators)
invoke:369, BatchTask (org.apache.flink.runtime.operators)
doRun:707, Task (org.apache.flink.runtime.taskmanager)
run:532, Task (org.apache.flink.runtime.taskmanager)
run:748, Thread (java.lang)

6.3 GroupReduceDriver & ChainedFlatMapDriver

這兩個放在一起,是因為他們組成了Operator Chain。

GroupReduceDriver.run中完成了reduce。具體reduce 操作是在 org.apache.flink.table.runtime.aggregate.DataSetFinalAggFunction.reduce 完成的,然後在其中直接發送給下游 out.collect(output)

@Override
public void run() throws Exception {
   // cache references on the stack
   final GroupReduceFunction<IT, OT> stub = this.taskContext.getStub();
 
   if (objectReuseEnabled) {
       ......	
   }
   else {
      final NonReusingKeyGroupedIterator<IT> iter = new NonReusingKeyGroupedIterator<IT>(this.input, this.comparator);
      // run stub implementation
      while (this.running && iter.nextKey()) {
         // stub.reduce 是用戶定義操作,runtime把某key對應的數據一次性傳給它
         stub.reduce(iter.getValues(), output);
      }
   }
}

從前文我們可以,這裏已經配置成了Operator Chain,所以out.collect(output)會調用到CountingCollector。CountingCollector的成員變量collector已經配置成了ChainedFlatMapDriver。

public void collect(OUT record) {
   this.numRecordsOut.inc();
   this.collector.collect(record);
}

this.collector = {ChainedFlatMapDriver@9643} 
 mapper = {FlatMapRunner@9610} 
 config = {TaskConfig@9655} 
 taskName = "FlatMap (select: (f0, mapToString($f1) AS type))"

於是程序就調用到了 ChainedFlatMapDriver.collect

public void collect(IT record) {
   try {
      this.numRecordsIn.inc();
      this.mapper.flatMap(record, this.outputCollector);
   } catch (Exception ex) {
      throw new ExceptionInChainedStubException(this.taskName, ex);
   }
}

最終調用棧如如下:

eval:21, UdfExample$MapToString (com.alibaba.alink)
flatMap:-1, DataSetCalcRule$14
flatMap:52, FlatMapRunner (org.apache.flink.table.runtime)
flatMap:31, FlatMapRunner (org.apache.flink.table.runtime)
collect:80, ChainedFlatMapDriver (org.apache.flink.runtime.operators.chaining)
collect:35, CountingCollector (org.apache.flink.runtime.operators.util.metrics)
reduce:80, DataSetFinalAggFunction (org.apache.flink.table.runtime.aggregate)
run:131, GroupReduceDriver (org.apache.flink.runtime.operators)
run:504, BatchTask (org.apache.flink.runtime.operators)
invoke:369, BatchTask (org.apache.flink.runtime.operators)
doRun:707, Task (org.apache.flink.runtime.taskmanager)
run:532, Task (org.apache.flink.runtime.taskmanager)
run:748, Thread (java.lang)

0x07 總結

由此我們可以看到:

  • GroupReduce,GroupCombine和mapPartition十分類似,都是從系統層面對算子進行優化,把循環操作放到用戶自定義函數來處理。
  • 對於group by這個SQL語句,Flink將其翻譯成 GroupReduce + GroupCombine,採用兩階段優化的方式來完成了對大數據下的處理。

0x08 參考

flink 使用問題匯總

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

salesforce零基礎學習(九十八)Type淺談

在Salesforce的世界,凡事皆Metadata。

先通過一句經常使用的代碼帶入一下:

Account accountItem = (Account)JSON.deserialize(accountString,Account.class);

這種代碼相信大部分開發都會寫過,前台將數據序列化,通過字符串的形參傳遞給後台,後台將數據進行反序列化,從而獲取到這個表或者這個自定義類的實例。所以問題來了,為啥第二個參數是 Account.class?我們通過官方的API描述可能更好的進行了解。

 這裏我們引出了 Type的概念,他是apex 預定的類型,包括 基礎數據類型(Integer等) , 集合, sObject類型以及 用戶定義的類。基礎數據類型等等都是 object類型,所以當我們理解salesforce裏面的類型時,可以簡單的分成兩個大類:Object & sObject。所以Type概念引入完了,它用來幹嘛?怎麼聲明?什麼時候用呢?

Type t1 = Integer.class;
Type t2 = Type.forName('Integer');
system.debug(t1.equals(t2));

上面的簡單的demo中提供了兩種聲明Type的方式,一種是根據 object | sObject使用 .class聲明,另外一種是使用 Type的方法forName來實例化變量。既然變量可以聲明出來,我們就可以看看他的方法考慮如何搞事情了。

 Type的方法非常少,所以我們想要查看其對應的方法描述以及使用很容易就看完。這裏針對幾個重要的方法進行描述:

  • forName(fullyQualifiedName):返回與指定的完全限定的類名相對應的類型。這裏的類名包括salesforce系統預製的類,自定義的類以及sObject名稱;
  • isAssignableFrom(sourceType):如果object指定類型的引用可以從子類型分配,則返回true,否則返回false。這個方法我們可能首先會先想到 instanceof,因為都是來判斷類型是否相兼容匹配,但是 instanceof必須是初始化這個類或者對象的變量,才能使用 instanceof 來進行判斷,使用 此方法可以省去了靜態編譯時的依賴,所以如果想判斷依賴性,可以優先考慮此方法。
  • newInstance():此方法用來實例化一個指定Type的對象,返回類型是一個object對象,我們可以強制轉換成我們需要的對象類型。因為apex也是面向對象的語言,封裝,繼承,多態三大特性,我們可以通過 newInstance實現父子類型的輕鬆轉換調用相關的方法從而實現動態配置。

基礎信息介紹完畢,此篇淺入淺出,介紹兩種可能用到的場景。

1.  JSON序列化與反序列化

這個我們經常使用,一筆帶過:通過字符串以及指定的 Type類型可以轉換成指定的數據類型。

Account accountItem = (Account)JSON.deserialize(accountString,Account.class);

2. 針對Custom Setting等根據配置的動態的類調用動態方法的使用

ParentClass是一個父類,有兩個變量以及一個虛擬的方法,繼承的子類可以進行實現

public abstract class ParentClass {
    public String param1 { get; set; }
    public String param2 { get; set; }

    public ParentClass() {
        this.param1 = 'value1';
        this.param2 = 'value2';
    }

    public virtual String joinParam() {
        return param1 + param2;
    }
}

SonClass1繼承了它並實現了它相關的方法

public class SonClass1 extends ParentClass {
    public SonClass1() {
        super();
        this.param1 = 'son value1';
        this.param2 = 'son value2';
    }

    public override String joinParam() {
        return super.joinParam();
    }
}

還有其他的SonClassn繼承了它並實現了它的相關的方法,我們在custom setting中配置了不同的場景應該調用的不同的子類,公共方法中,我們只需要使用以下的代碼來判斷和調用即可。

public String executeJoin(String className) {
    Type t = Type.forName(className);
    Type t2 = Type.forName('ParentClass');
    if(!t2.isAssignableFrom(t)) {
        throw new CustomException('should be son class of ParentClass');
    }
    ParentClass newObj = (ParentClass)t.newInstance();
    return newObj.joinParam();
}

總結:篇中簡單的介紹了salesforce中的 Type的使用,拋磚引玉,想要深入了解還要自行查看官方文檔。篇中有錯誤的地方歡迎指出,有不懂的歡迎留言。

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

【其他文章推薦】

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

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

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

※超省錢租車方案

FB行銷專家,教你從零開始的技巧

Nginx服務器的使用與反向代理負載均衡

Nginx服務器

一:什麼是Nginx?

我們生活的世界中,有的時候需要上網。我們可以瀏覽很多很多的網頁,這些網頁都是由一系列的程序組成,但是我們是否想過,這些程序存儲在什麼地方呢?沒錯,這些程序都是存儲在一種名叫服務器的硬件上,比如我們的電腦也是一種服務器,只不過我們的個人電腦作為服務器的話性能會比較低。我們的網頁程序存儲在服務器硬件上,是否可以隨意存儲呢?不是的,我們需要在服務器硬件的操作系統中搭建一個服務器軟件,那麼這樣,有服務器軟件跟服務器硬件配合,才形成一個完整的服務器。服務器軟件有非常多,比如Apache、tomcat等等都是服務器軟件,而我們今天要學習的Nginx也是一種服務器軟件之一。

Nginx是一種服務器軟件,故而其最主要、最基本的功能當然是可以與服務器硬件結合,讓程序員可以將程序放在Nginx服務器上,將程序發布出去,讓成千上萬的網民可以瀏覽。除此之外,Nginx是一種高性能的HTTP和反向代理服務器,同時也是一個代理郵件服務器。也就是說,我們Nginx上可以發布網站,也可以實現負載均衡的功能,還可以作為郵件服務器實現收發郵件等功能。所謂的負載均衡是指,當同時有N多用戶訪問我們服務器的時候,為了減少服務器壓力,我們需要將用戶分別引入各服務器,分擔服務器的壓力。

Nginx與其他服努器的性能比較

首先說IIS, IIS服務器只能在Windows上運行,Windows服務器性能不如Linux— 類服務器。其次說Tomcat,Tomcat服務器面向的是Java語言,是一種重量級的服 務器,而Nginx是輕量級服務器,Tomcat與Nginx不具備可比性。最後,我們講一 下Apache,Apache優點非常多,比如穩定、幵源、跨平台等等,但是Apache不支 持高併發。Nginx能支持處理百萬級的TCP連接,10萬以上的併發連接,並且是一 個很好的跨平台服務器。

Nginx的主要優點有可以實現高併發、部署簡單、內存消耗少、成本低等等。

Nginx的主要缺點有rewrite功能不夠強大,模塊沒有Apache的多。

本文版權歸微信公眾號”代碼藝術”(ID:onblog)所有,若是轉載請務必保留本段原創聲明,違者必究。若是文章有不足之處,歡迎關注微信公眾號私信與我進行交流!

二:Linux中搭建Nginx服務器

新建壓縮包下載位置(可選)

新建目錄
mkdir /usr/local/nginx_down
切換目錄
cd /usr/local/nginx_down

下載解壓 Nginx

下載
wget http://nginx.org/download/nginx-1.14.0.tar.gz
解壓
tar -zxvf nginx-1.14.0.tar.gz
切換目錄
cd nginx-1.14.0

配置 Nginx

./configure --with-http_ssl_module
  1. 這樣會默認安裝nginx在 /usr/local/nginx 目錄,可以使用--prefix=/usr/local/nginx指定安裝位置。

  2. 如果需要HTTPS(SSL)的支持,需要指定參數--with-http_ssl_module

如果提示錯誤,那麼需要其它環境,請參考下面

安裝 make

yum -y install gcc automake autoconf libtool make

安裝 g++

yum -y install gcc gcc-c++

安裝 PCRE庫

yum -y install pcre pcre-devel

安裝 Zlib

yum -y install zlib zlib-devel

安裝 GD library

yum -y install gd-devel

安裝 openssl

yum -y install openssl openssl-devel

-y:跳過所有手動確認輸入

如果./configure安裝成功,只需要再執行兩個命令:

make
make install

查看是否安裝成功

cd /usr/local/nginx

如果安裝成功,則會出現下列目錄:

conf  html  logs  sbin

切換到sbin目錄

cd /sbin

啟動程序

./nginx

追加參數 -c 可以指定配置文件。

常見的錯誤

在Linux操作系統下搭建Nginx服務器,很多時候會出現不同的錯誤,在此,我們對搭建過程中出現的錯誤進行一些總結。主要有這些類型:

防火牆問題,缺少gc++,缺少pcre、zlib等庫。

三:Nginx的反向代理和負載均衡

什麼是反向代理

我們有時候,用自己的計算機A想訪問國外的某個網站B,但是訪問不了,此時,有一台中間服務器C可以訪問國外的網站B,那麼,我們可以用自己的電腦訪問服務器C,通過C來訪問B這個網站。那麼這個時候,服務器C稱為代理服務器,這種訪問方式叫做正向代理。正向代理有一個特點,就是我們明確知道要訪問哪個網站。再如,當我們有一個服務器集中,並且服務器集群中的每台服務器的內容一樣的時候,同樣我們要直接從個人電腦訪問到服務器集中的服務器的時候無法訪問,且此時第三方服務器能訪問集群,這個時候,我捫通過第三方服務器訪問服務器集群的內容,但是此吋我們並不知道是哪一台服務器提供的內容,此時的代理方式稱為反向代理。

正向代理

反向代理

什麼是負載均衡

當一台服務器的單位時間內的訪問量越大的時候,服務器的壓力會越大。當一台服務器壓力大得超過自身的承受能力的時候,服務器會崩潰。為了避免服務器崩潰,讓用戶有更好地體驗,我們通常通過負載均衡的方式來分擔服務器的壓力。那麼什麼是負載均衡呢?是這樣,我們可以建立很多很多個服務器,這些服務器組成一個服務器集群,然後,當用戶訪問我們網站的時候,先訪問一个中間服務器,再讓這个中間服務器在服務器集群中選擇一個壓力較小的服務器,然後將該訪問請求引入該選擇的服務器。這樣,用戶的每次訪問,都會保證服務器集群中的每個服務器的壓力趨於平衡,分擔了服務器壓力,避免了服務器崩潰的情況。

基於反向代理的原理實現負載均衡

四:Nginx負載均衡的實現

Nginx 是一款可以通過反向代理實現負載均衡的服務器,使用 Nginx 服務實現負載均衡的時候,用戶的訪問首先會訪問到 Nginx 服務器,然後 Nginx 服務器再從服務器集群表中選擇壓力較小的服務器,然後將該訪問請求引向該服務器。若服務器集群中的某個服務器崩潰,那麼從待選服務器列表中將該服務器刪除,也就是說一個服務器假如崩潰了,那麼 Nginx 就肯定不會將訪問請求引入該服務器了。那麼下面,我們通過實例來講解一下 Nginx 負載均衡的實現。

負載均衡配置文件

默認配置文件nginx.conf 很重要,我們一般是新建一個配置文件,在啟動時指定加載。

[root@hostname conf]# ls  //查看目錄
fastcgi.conf            koi-win             scgi_params
fastcgi.conf.default    mime.types          scgi_params.default
fastcgi_params          mime.types.default  uwsgi_params
fastcgi_params.default  nginx.conf          uwsgi_params.default
koi-utf                 nginx.conf.default  win-utf
[root@hostname conf]# touch fzjh.conf  //新建負載均衡配置文件

編輯fzjh.conf配置文件

vi fzjh.conf
worker_processes  1;#工作進程的個數,一般與計算機的cpu核數一致  
  
events {  
    worker_connections  1024;#單個進程最大連接數(最大連接數=連接數*進程數) 併發 
}  
  
http {  
    include       mime.types; #文件擴展名與文件類型映射表  
    default_type  application/octet-stream;#默認文件類型  
  
    sendfile        on;#開啟高效文件傳輸模式,sendfile指令指定nginx是否調用sendfile函數來輸出文件,對於普通應用設為 on,如果用來進行下載等應用磁盤IO重負載應用,可設置為off,以平衡磁盤與網絡I/O處理速度,降低系統的負載。注意:如果圖片显示不正常把這個改成off。  
      
    keepalive_timeout  65; #長連接超時時間,單位是秒  
  
    gzip  on;#啟用Gizp壓縮  
      
    #服務器的集群  
    upstream  myproject {  #服務器集群名字   
        server    220.181.111.188:80  weight=1;#服務器配置   weight是權重的意思,權重越大,分配的概率越大。  
        server    42.121.252.58:80  weight=2;  
    }     
  
    #當前的Nginx的配置  
    server {  
        listen       80;  #監聽80端口,可以改成其他端口  
        server_name  localhost; ##############   當前服務的域名  
  
        location / {  ##配置路徑/下實現負載均衡
            proxy_pass http://myproject;  ##對應哪個服務器集群
            proxy_redirect default;  
        }  
          
        error_page   500 502 503 504  /50x.html;  
        location = /50x.html {  
           root   html;  #根目錄
        }  
    }  
}  

我們在nginx目錄下執行命令,啟動負載均衡

./sbin/nginx -c ./conf/fzjh.conf

然後嘗試訪問你的服務器,多訪問幾次,你會發現它會訪問2次csdn網站,1次百度。說明我們的負載均衡已經部署完畢。

如何重啟Nginx

【本文版權歸微信公眾號”代碼藝術”(ID:onblog)所有,若是轉載請務必保留本段原創聲明,違者必究。若是文章有不足之處,歡迎關注微信公眾號私信與我進行交流!】

./sbin/nginx -s reload

如何關閉Nginx服務器

1.查看nginx進程號

ps -ef|grep nginx

2.kill掉進程即可 (1709是第二列的進程號)

kill 1709

或者

killall -9 nginx

五:HTTP Upstream 模塊

HTTP Upstream 模塊

Upstream 模塊是 Nginx 服務器的一個重要模塊。 Upstream 模塊實現在輪詢和客戶端 iP 之間實現後端的負載均衡。常用的指令有 ip_hash指令、 server 指令和 upstream 指令等,下面我們分別來講一下。

Http Upstream模塊- ip_hash指令

在負載均衡系統中,假如用戶在某台服務器上登錄,那麼如果該用戶第二次請求的時候,因為我們是負載均衡系統,每次請求都會重新定位到服務器集群中的一個服務器,那麼此時如果將已經登錄服務器A的用戶再定位到其他服務器,顯然不妥。故而,我們可以採用 ip_hash指令解決這個問題,如果客戶端請求已經訪問了服務器A並登錄,那麼第二次請求的時候,會將該請求通過哈希算法自動定位到該後端服務器中。下面我們通過實例講解。

實例

此時不應該使用weight權重。


tp {  
   ....
  upstream  myproject {    
      ip_hash; #實現會話跟蹤
      server 140.205.140.234;
      server 61.135.169.125;

  }     
 ....

Http Upstream 模塊一 upstream 指令及相關變量

upstream 指令主要是用於設置一組可以在 proxy_pass 和 fastcgi_pass 指令中使用代理服務器,默認負載均衡方式為輪詢。

六:其他負載均衡實現方式

負載均衡的實現方法除了可以使用 Nginx服務器實現外,還可以通過很多種方法來實現。負載均衡的核心就是建立一個服務器集群,然後用戶首先訪問到第三方代理服務器,然後由代理服務器選擇一個集群中的服務器,然後將請求引入選定的服務器。那麼代理服務器可以使用多種方式來充當,故而實現負載均衡的方式也是多種。總的來說,負載均衡實現的方式分為軟件實現和硬件實現兩種,如果中間的代理機構是硬件,那麼就是通過硬件設備來實現負載均衡的方式,如果中間的代理機構為軟件,就是軟件實現負載均衡的方式。而其中,軟件又可以是服務器軟件、系統軟件以及應用軟件等充當。

負載均衡實現方式小結

下面我們簡單總結一下負載均衡不同實現方式的優缺點:

假如使用硬件的方式實現負載均衡,那麼中間的轉發機構就是硬件,這個時候運行的效率非常高,但是對應的成本也非常高。如果我們採用軟件的方式來實現負載均衡,那麼中間的轉發機構就是軟件,這個時候,運行效率不如硬件,但是成本相對來說低得多。而使用Nginx服務器實現負載均衡,那麼就是通過軟件的方式來實現負載均衡,並且 Nginx本身支持高併發等。故而使用 Nginx服務器實現負載均衡,能大大節約企業的成本,並且由於 Nginx是服務器軟件,其執行效率也是非常高。

七:location匹配順序

  1. “=”前綴指令匹配,如果匹配成功,則停止其他匹配
  2. 普通字符串指令匹配,順序是從長到短,匹配成功的location如果使用^~,則停止其他匹配(正則匹配)
  3. 正則表達式指令匹配,按照配置文件里的順序,成功就停止其他匹配
  4. 如果第三步中有匹配成功,則使用該結果,否則使用第二步結果

注意點

  1. 匹配的順序是先匹配普通字符串,然後再匹配正則表達式。另外普通字符串匹配順序是根據配置中字符長度從長到短,也就是說使用普通字符串配置的location順序是無關緊要的,反正最後nginx會根據配置的長短來進行匹配,但是需要注意的是正則表達式按照配置文件里的順序測試。找到第一個比配的正則表達式將停止搜索。
  2. 一般情況下,匹配成功了普通字符串location后還會進行正則表達式location匹配。有兩種方法改變這種行為,其一就是使用“=”前綴,這時執行的是嚴格匹配,並且匹配成功后立即停止其他匹配,同時處理這個請求;另外一種就是使用“^~”前綴,如果把這個前綴用於一個常規字符串那麼告訴nginx 如果路徑匹配那麼不測試正則表達式。

匹配模式及順序

  location = /uri    =開頭表示精確匹配,只有完全匹配上才能生效。

  location ^~ /uri   ^~ 開頭對URL路徑進行前綴匹配,並且在正則之前。

  location ~ pattern  ~開頭表示區分大小寫的正則匹配。

  location ~* pattern  ~*開頭表示不區分大小寫的正則匹配。

  location /uri     不帶任何修飾符,也表示前綴匹配,但是在正則匹配之後。

  location /      通用匹配,任何未匹配到其它location的請求都會匹配到,相當於switch中的default。

八:配置HTTPS

1.獲取證書

獲得SSL證書文件 1_www.domain.com_bundle.crt 和私鑰文件 2_www.domain.com.key

2.證書安裝

將域名 www.domain.com 的證書文件1_www.domain.com_bundle.crt 、私鑰文件2_www.domain.com.key保存到同一個目錄,例如/usr/local/nginx/conf目錄下。

3.配置conf

打開nginx.conf文件,找到nginx.conf的下段配置內容:

# HTTPS server
#
#server {
#    listen       443 ssl;
#    server_name  localhost;

#    ssl_certificate      cert.pem;
#    ssl_certificate_key  cert.key;

#    ssl_session_cache    shared:SSL:1m;
#    ssl_session_timeout  5m;

#    ssl_ciphers  HIGH:!aNULL:!MD5;
#    ssl_prefer_server_ciphers  on;

#    location / {
#        root   html;
#        index  index.html index.htm;
#    }
#}

打開註釋,修改server_name為綁定證書的域名(如:www.domain.com),修改ssl_certificate 為 1_www.domain.com_bundle.crt,修改 ssl_certificate_key 為 2_www.domain.com.key 即可。

4.HTTP自動跳轉HTTPS

對於用戶不知道網站可以進行https訪問的情況下,讓服務器自動把http的請求重定向到https。 在服務器這邊的話配置的話,可以在頁面里加js腳本,也可以在後端程序里寫重定向,當然也可以在web服務器來實現跳轉。

Nginx是支持rewrite的(只要在編譯的時候沒有去掉pcre) 在http的server里增加rewrite ^(.*) https://$host$1 permanent; 這樣就可以實現80進來的請求,重定向為https了。

還是在此配置文件中,加入下面一句:

server {
        listen       80;
        server_name  localhost;
        
		rewrite ^(.*) https://$host$1 permanent;
		...

版權聲明

本文版權歸微信公眾號”代碼藝術”(ID:onblog)所有,若是轉載請務必保留本段原創聲明,違者必究。若是文章有不足之處,歡迎關注微信公眾號私信與我進行交流!

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

drf之框架基礎

(一)drf基礎

全稱:django-rest framework

接口:什麼是接口、restful接口規範(協議)

CBV(基於FBV的基礎上形成)、CBV生命周期源碼—-基於restful規範下的CBV接口

請求生命周期:請求組件、解析組件、響應組件

序列化組件(序列化、反序列化簡單來說就是對象轉為字符串、字符串轉為對象,目的是為傳輸數據(傳給別的語言或者存儲))

三大認證(重中之重):認證(用戶是否合法)、權限(管理員、普通用戶)、頻率(次數過多限制)

其他組件(過濾、篩選、排序、分頁、路由)

 

1.接口

概念:聯繫兩個物質的媒介,完成信息的交互。在web程序中,聯繫前台頁面後台數據庫的媒介。

web接口組成:

url:長得像返回數據的url鏈接。如api.baidu.map/search

www.baidu.com不叫接口,叫url鏈接,訪問只能拿到主頁。api.baidu.map/search是接口,返回的是json數據)

請求參數:前台按照指定的key提供數據給後台。(必須是給定的,這樣後台才能以此提取數據再到數據庫查詢返回)

響應數據:後台與數據庫交互后,將數據反饋給前台。

因此,接口就是帶着請求參數訪問能夠得到響應數據的url鏈接。

接口 = url + 請求參數 + 響應數據

 

 

2.restful接口規範

接口規範:不同後台語言,使用同樣的接口返回同樣的數據。

如何寫接口:要寫url和響應數據。如果將請求參數也加上,就是在寫接口文檔。

 

兩大部分:

1url

1)用api關鍵字標識接口url。方式1api.baidu.com;方式2:www.baudu.com/api

2)接口數據安全性決定優先選用https協議

3)如果一個接口有多版本存在,需要在url中標識體現。如下的v1v2

api.baidu.com/v1/….  api.baidu.com/v2/….

4)操作中的數據稱為資源,在url中資源一般採用複數形式,一個接口可以概括對該資源的多種操作方式。(一個url對應一個類,類裏面可以有多個請求方法)

可以對操作隱藏,並且復用性更強(寫動作了,只能適用這一個動作,不寫其他動作都可以用)如api.baidu.com/books    api.baidu.com/books/(pk)

5)請求方式有多種,用一個url處理如何讓保證不混亂——通過不同的請求方式標識不同操作資源的方式

/books      get     獲取所有

/books post   增加一個(多個)

/books/(pk) delete 刪除一個

/books/(pk)  put 整體更新一個  #改一個用戶

/books/(pk)  patch 局部更新一個 #改一個用戶的密碼

 

6)資源往往涉及數據的各種操作方式:篩選、排序、限制

api.baidu.com/books/?search=寶馬&ordering=-price&limit=3

 

2)響應數據

1http請求的響應會有響應狀態碼,接口用來返回操作的資源數據,也有自己操作數據結果的資源狀態碼status 0代表操作資源成功,1代表操作失敗,2代表操作成功,但沒匹配結果)

注:資源狀態碼和http狀態碼不一樣,為前後台的約定

2)資源狀態碼的文字提示。

status ok “賬號有誤或者密碼有誤”

3)資源本身

results

:刪除資源成功不做任何數據返回(只返回空字符串,連狀態碼、狀態信息都不返回)

4)不能直接返回的資源(子資源、圖片、視頻等資源),返回該資源的url鏈接。

 

https://api.baidu.com/v1/books?limit=3
get|post|delete|put|patch   
{
  “status” : 0,
  “msg” : “ok”,
  “results”: [
{
  “title”: “三國”,
  “price”: 78,
  “img”: “https://.....”   
    }
  ]
}

 

3.django流程

1)項目準備:

 

1.分發路由

在項目文件夾的urls複製一份到應用文件夾中。然後在項目文件夾的urls分發路由給app:導入include,然後url(r’^api/’, include(‘api.urls’))。再在app文件夾的urls.py中分發路由給CBV

2.視圖

在應用中分發路由前,先寫類視圖

from django.http import JsonResponse
from django.views import View

class Book(View):

    def get(self, request, *args, **kwargs):
        return JsonResponse('get ok', safe=False)

    def post(self, request, *args, **kwargs):
        return JsonResponse('get ok', safe=False)   #safe默認為true,要返回字典。不是字典否則拋異常。

 

3.在應用urls下分發路由

from django.conf.urls import url
from . import views    #注意在應用中導入視圖都是.   從當前應用中導入

urlpatterns = [
    url(r'^books/', views.Book.as_view()),
]

 

4.定義模型類

1models.py中定義類

from django.db import models

class Book(models.Model):

    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=5, decimal_places=2) #整數、小數位

    class Meta:    #嵌套類(給上級類添加功能或指定標準)
        
       db_table = 'book'    #自定義數據庫表名
        verbose_name = "book"   #給模型起個可讀的名字,默認是複數
        verbose_name_plural = verbose_name   #取消上面的複數

    def __str__(self):      #显示的內容
        return '<<%s>>' % self.title    

 

 

   (2)數據庫遷移

進入djangoshell環境中:Tools—-> run manage.py task

shell環境中生成遷移文件:makemigrations。然後遷移:migrate

 

5.生成admin

1)在amin.py中註冊並且導入模型

from django.contrib import admin
port models

admin.site.register(models.Book)

 

2)創建用戶

shell環境中:createsuper創建超級用戶,然後輸入用戶密碼(郵箱不用)

 

 

 2CBV的請求生命周期

請求如何到CBV下的getpost

a.請求過來,項目文件中路由分發給應用api的路由

b.應用分發路由走as_view函數。

views.Book.as_view()  保存一系列數據(requestargs**kwargs等)給Book對象,然後都給dispatch進行路由分發。

dispatch乾的事:判斷請求方式是否支持,然後返回(通過getattr)支持的這些請求方法(getpost等,在視圖中自定義getpost的返回值)的結果。

c.通過dispatch就執行了CBV下請求方式的結果,返回結果

 

 

4.django原生的接口、序列化

  六大基礎接口:獲取一個、獲取所有、增加一個、刪除一個、整體更新一個、局部更新一個

 十大接口:6大基礎、群增、群刪、整體群改、局部群改

 

1.在應用的urls.py下分發路由

url(r’^books/$’, views.Book.as_view()),   #必須要加$,否則後面匹配不到

url(r’^books/(?P<pk>.*)/$’, views.Book.as_view()),有名分組

在視圖函數中通過kwargs.get(pk)取到匹配的值

 

2.views.py里寫邏輯

class Book(View):

 

    def get(self, request, *args, **kwargs):

        pk = kwargs.get(‘pk’)  #獲取參數

        if not pk:  #群查接口

            #操作數據庫

            book_obj_list = models.Book.objects.all()

            #序列化過程

            book_list = []

            for obj in book_obj_list:   #將查到的對象序列化

                dic = {}

                dic[‘title’] = obj.title

                dic[‘price’] = obj.price

                book_list.append(dic)

            return JsonResponse({

                ‘status’ : 0,

                “msg” : “ok”,

                “results”: book_list,

            }, json_dumps_params={‘ensure_ascii’:False})

        else:    #單查接口

            book_dic = models.Book.objects.filter(pk=pk).values(

                ‘title’, ‘price’).first()

            if book_dic:

                return JsonResponse({

                    ‘status’: 0,

                    “msg”: “ok”,

                    “results”: book_dic,

                }, json_dumps_params={‘ensure_ascii’: False})

 

            return JsonResponse({

                ‘status’: 2,

                “msg”: “no results”,

            }, json_dumps_params={‘ensure_ascii’: False})

 

 

    def post(self, request, *args, **kwargs):

        #前台通過urlencoded方式提交數據

        try:

            book_obj = models.Book.objects.create(**request.POST.dict()) #create創建對象。將request.POST中存放的提交的關鍵詞參數轉化為字典以**方式傳進去。沒傳參數,這邊會報錯。

            if book_obj:

                return JsonResponse({

                ‘status’: 0,

                “msg”: “ok”,

                “results”: {‘title’:book_obj.title, “price”:book_obj.price}

            }, json_dumps_params={‘ensure_ascii’: False})

        except:    #健壯性

            return JsonResponse({

                ‘status’: 1,

                “msg”: “wrong params”,

            }, json_dumps_params={‘ensure_ascii’: False})

        return JsonResponse({    #可能操作數據庫失敗了

                ‘status’: 2,

                “msg”: “created failed”,

            }, json_dumps_params={‘ensure_ascii’: False})

           

  

JsonResponse返回時,中文會變成unicode,要加json_dumps_params={‘ensure_ascii’:False}選項。但在linux環境下的火狐瀏覽器,加了是亂碼。

 

filter返回queryset對象,對象里是個列表(表名:對象信息(有自定義str就是自定義的信息))。first取里第一個對象(相當於print(第一個對象)values展示對應的對象里的值

<QuerySet [<Book: <<三國演義>>>]>                   #直接.filter

<<三國演義>>                                    #.first()

<QuerySet [{‘title’: ‘三國演義‘, ‘price’: Decimal(‘56.00’)}]>  #.values(‘title’,’price’)

{‘title’: ‘三國演義‘, ‘price’: Decimal(‘56.00’)}             #.values.first()  是個字典

 

 上面序列化的工作很麻煩。drf就是為了方便序列化的。

 

postman可以完成不同方式的請求:getpostput

postman發送數據包有三種方式:form-dataurlencodedjson. 原生djangourlencoded數據提交兼容。

 

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

『圖論』LCA 最近公共祖先

概述篇

LCA (Least Common Ancestors) ,即最近公共祖先,是指這樣的一個問題:在一棵有根樹中,找出某兩個節點 uv 最近的公共祖先。

LCA 可分為在線算法離線算法

  • 在線算法:指程序可以以序列化的方式一個一個處理輸入,也就是說在一開始並不需要知道所有的輸入。
  • 離線算法:指一開始就需要知道問題的所有輸入數據,而在解決一個問題后立即輸出結果。

算法篇

對於該問題,很容易想到的做法是從 u、v 分別回溯到根節點,然後這兩條路徑中的第一個交點即為 u、v 的最近公共祖先,在一棵平衡二叉樹中,該算法的時間複雜度可以達到 O(logn)O(log⁡n) ,但是對於某些退化為鏈狀的樹來說,算法的時間複雜度最壞為 O(n)O(n) ,顯然無法滿足更高頻率的查詢。

本節將介紹幾種比較高效的算法來解決這一問題,常見的算法有三種:在線 DFS + ST 算法、倍增算法、離線 Tarjan 算法。

接下來我們來一一解釋這三種 /* 看似高深,其實也不簡單 */ 的算法。

在線 DFS + ST 算法

首先看到 ST 你會想到什麼呢?(腦補許久都沒有想到它會是哪個單詞的縮寫)

看過前文 『數據結構』RMQ 問題 的話你便可以明白 ST算法 的思路啦~

So ,關於 LCA 的這種在線算法也是可以建立在 RMQ 問題的基礎上咯~

我們設 LCA(T,u,v) 為在有根樹 T 中節點 u、v 的最近公共祖先, RMQ(A,i,j) 為線性序列 A 中區間 [i,j] 上的最小(大)值。

如下圖這棵有根樹:

我們令節點編號滿足父節點編號小於子節點編號(編號條件)

可以看出 LCA(T,4,5) = 2, LCA(T,2,8) = 1, LCA(T,3,9) = 3

設線性序列 A 為有根樹 T 的中序遍歷,即 A = [4,2,5,1,8,6,9,3,7]

由中序遍歷的性質我們可以知道,任意兩點 u、v 的最近公共祖先總在以該兩點所在位置為端點的區間內,且編號最小。

舉個栗子:

假設 u = 8, v = 7 ,則該兩點所確定的一段區間為 [8,6,9,3,7] ,而區間最小值為 3 ,也就是說,節點 3u、v 的最近公共祖先。

解決區間最值問題我們可以採用 RMQ 問題中的 ST 算法

但是在有些問題中給出的節點並不一定滿足我們所說的父節點編號小於子節點編號,因此我們可以利用節點間的關係建圖,然後採用前序遍歷來為每一個節點重新編號以生成線性序列 A ,於是問題又被轉化為了區間最值的查詢,和之前一樣的做法咯~

時間複雜度: n×O(logn)n×O(log⁡n) 預處理 + O(1)O(1) 查詢

想了解 RMQ 問題 的解法可以戳上面的鏈接哦~

以上部分介紹了 LCA 如何轉化為 RMQ 問題,而在實際中這兩種方案之間可以相互轉化

類比之前的做法,我們如何將一個線性序列轉化為滿足編號條件的有根樹呢?

  1. 設序列中的最小值為 AkAk ,建立優先級為 AkAk 的根節點 TkTk
  2. 將 A[1…k−1]A[1…k−1] 遞歸建樹作為 TkTk 的左子樹
  3. 將 A[k+1…n]A[k+1…n] 遞歸建樹作為 TkTk 的右子樹

讀者可以試着利用此方法將之前的線性序列 A = [4,2,5,1,8,6,9,3,7] 構造出有根樹 T ,結果一定滿足之前所說的編號條件,但卻不一定唯一。

離線 Tarjan 算法

Tarjan 算法是一種常見的用於解決 LCA 問題的離線算法,它結合了深度優先搜索與並查集,整個算法為線性處理時間。

首先來介紹一下 Tarjan 算法的基本思路:

  1. 任選一個節點為根節點,從根節點開始
  2. 遍歷該點 u 的所有子節點 v ,並標記 v 已經被訪問過
  3. 若 v 還有子節點,返回 2 ,否則下一步
  4. 合併 v 到 u 所在集合
  5. 尋找與當前點 u 有詢問關係的點 e
  6. 若 e 已經被訪問過,則可以確定 u、e 的最近公共祖先為 e 被合併到的父親節點

偽代碼:

Tarjan(u)               // merge 和 find 為並查集合併函數和查找函數
{
    for each(u,v)       // 遍歷 u 的所有子節點 v
    {
        Tarjan(v);      // 繼續往下遍歷
        merge(u,v);     // 合併 v 到 u 這一集合
        標記 v 已被訪問過;
    }
    for each(u,e)       // 遍歷所有與 u 有查詢關係的 e
    {
        if (e 被訪問過)
            u, e 的最近公共祖先為 find(e);
    }
}
C++

感覺講到這裏已經沒有其它內容了,但是一定會有好多人沒有理解怎麼辦呢?

我們假設在如下樹中模擬 Tarjan 過程(節點數量少一點可以畫更少的圖o( ̄▽ ̄)o)

存在查詢: LCA(T,3,4)、LCA(T,4,6)、LCA(T,2,1)

注意:每個節點的顏色代表它當前屬於哪一個集合,橙色線條為搜索路徑,黑色線條為合併路徑。

當前所在位置為 u = 1 ,未遍歷孩子集合 v = {2,5} ,向下遍歷。

當前所在位置為 u = 2 ,未遍歷孩子集合 v = {3,4} ,向下遍歷。

當前所在位置為 u = 3 ,未遍歷孩子集合 v = {} ,遞歸到達最底層,遍歷所有相關查詢發現存在 LCA(T,3,4) ,但是節點 4 此時標記未訪問,因此什麼也不做,該層遞歸結束。

遞歸返回,當前所在位置 u = 2 ,合併節點 3u 所在集合,標記 vis[3] = true ,此時未遍歷孩子集合 v = {4} ,向下遍歷。

當前所在位置 u = 4 ,未遍歷孩子集合 v = {} ,遍歷所有相關查詢發現存在 LCA(T,3,4) ,且 vis[3] = true ,此時得到該查詢的解為節點 3 所在集合的首領,即 LCA(T,3,4) = 2 ;又發現存在相關查詢 LCA(T,4,6) ,但是節點 6 此時標記未訪問,因此什麼也不做。該層遞歸結束。

遞歸返回,當前所在位置 u = 2 ,合併節點 4u 所在集合,標記 vis[4] = true ,未遍歷孩子集合 v = {} ,遍歷相關查詢發現存在 LCA(T,2,1) ,但是節點 1 此時標記未訪問,因此什麼也不做,該層遞歸結束。

遞歸返回,當前所在位置 u = 1 ,合併節點 2u 所在集合,標記 vis[2] = true ,未遍歷孩子集合 v = {5} ,繼續向下遍歷。

當前所在位置 u = 5 ,未遍歷孩子集合 v = {6} ,繼續向下遍歷。

當前所在位置 u = 6 ,未遍歷孩子集合 v = {} ,遍歷相關查詢發現存在 LCA(T,4,6) ,且 vis[4] = true ,因此得到該查詢的解為節點 4 所在集合的首領,即 LCA(T,4,6) = 1 ,該層遞歸結束。

遞歸返回,當前所在位置 u = 5 ,合併節點 6u 所在集合,並標記 vis[6] = true ,未遍歷孩子集合 v = {} ,無相關查詢因此該層遞歸結束。

遞歸返回,當前所在位置 u = 1 ,合併節點 5u 所在集合,並標記 vis[5] = true ,未遍歷孩子集合 v = {} ,遍歷相關查詢發現存在 LCA(T,2,1) ,此時該查詢的解便是節點 2 所在集合的首領,即 LCA(T,2,1) = 1 ,遞歸結束。

至此整個 Tarjan 算法便結束啦~

PS:不要在意最終根節點的顏色和其他節點顏色有一點點小小差距,可能是在染色的時候沒仔細看,總之就這樣咯~

PPS:所謂的首領就是、就是首領啦~

倍增算法

哇!還有一個倍增算法以後繼續補充吧!

總結篇

對於不同的 LCA 問題我們可以選擇不同的算法。

假若一棵樹存在動態更新,此時離線算法就顯得有點力不從心了,但是在其他情況下,離線算法往往效率更高(雖然不能保證得到解的順序與輸入一致,不過我們有 sort 呀)

總之,喜歡哪種風格的 code 是我們自己的意願咯~

另外, LCA 和 RMQ 問題是兩個非常基礎的問題,很多複雜問題都可以轉化為這兩類問題來解決。(當然這兩類問題之間也可以相互轉化啦~)

參考資料

OI wiki https://oi-wiki.org/graph/lca/

https://blog.csdn.net/my_sunshine26/article/details/72717112

https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/03.03.html

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

FB行銷專家,教你從零開始的技巧