標籤: 銷售文案

  • 民主非人類專利 這三種動物也會選舉罷免

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

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

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

  • 動力更強,更好開還更省油,以後可以買到這些車

    動力更強,更好開還更省油,以後可以買到這些車

    以前總說手動擋車型省油,但現在不少自動變速箱與發動機的匹配愈發爐火純青,油耗也持續往下走,有些自動擋車型的油耗數據完全不輸手動擋。曾經我認為四缸是一台車的底線,沒想到現在三缸機已經越來越普遍。最經典的就是寶馬1系,連一向對發動機輸出有苛刻要求的寶馬都推出了1。

    隨着我國經濟的飛速發展,不少人民的錢包變得越來越鼓。近幾年,我國汽車的人均汽車保有量在迅速攀升,銷量已經連續幾年位居世界第一。各國的廠商已經越來越重視中國市場,甚至有不少車型都是為中國市場量身定做的。

    這十幾年中國汽車市場的變化還是挺大的,但這些變化我個人認為並不能說都是好事,只能說是一種對現實的妥協,下面就來和大家談談那些變化。

    在08年左右的時候,自然吸氣發動機的車還是大行其道,那時候對排放沒有捉得這麼嚴,所以各路廠家都喜歡推出自吸車。我自己家裡也有一輛1.6L老世嘉,一腳油門下去時,加速力雖然不是很猛,但循序漸進的感覺確實美妙。

    到了現在2018年,自吸車雖然不至於說退出歷史舞台,但是佔比已經愈來愈低,渦輪車的普及程度越來越高。早些年的時候,渦輪還是比較容易壞的。不過經過這麼多年的發展,渦輪的耐用性得以大幅提升。

    連一向崇尚自吸的日系車都大力推渦輪,就知道這個趨勢已經不可逆轉。不過日系車的渦輪車普遍體驗還是不錯的,像1.5T的思域、2.0T的漢蘭達都給消費者帶來了良好的駕乘質感。自吸這條路,目前也只有日產和馬自達等寥寥無幾的車企在苦苦支撐。

    在過去的時候,雖然也有自動擋,但普及程度沒有現在這麼高。現在感覺10台車裡面有9台都是自動擋的,而大多數人估計拿了駕駛證以後就沒有再開過手動擋,也有不少女生是直接考了個C2駕照。

    自動擋車型的門檻越來越低,這對於廣大消費者來講絕對是一件好事,畢竟不是所有人都喜歡開車這件事。以前總說手動擋車型省油,但現在不少自動變速箱與發動機的匹配愈發爐火純青,油耗也持續往下走,有些自動擋車型的油耗數據完全不輸手動擋。

    曾經我認為四缸是一台車的底線,沒想到現在三缸機已經越來越普遍。最經典的就是寶馬1系,連一向對發動機輸出有苛刻要求的寶馬都推出了1.5T三缸發動機來搶佔更多的市場份額。

    雖然現在的三缸機在抖動控制方面已經做得相當不錯,在車內如果不是仔細體會,還真不容易感覺出來。不過也有一些汽修人員指出,三缸機在老化以後,抖動要比四缸機明顯不少,這也是不少人擔心的地方。

    儘管如此,隨着汽車技術的不斷髮展,三缸機的技術也會得到進一步優化。就像別克的英朗、閱朗和GL6已經全面三缸化,未來相信會有越來越多的車型加入其中。

    在各種政策的大力鼓勵下,各種電動車企業像雨後春筍般湧現出來,不少品牌連我們都不大認識。毫無疑問電動車會是下一片紅海,很多企業都想從中分一杯羹。不過就目前來看,自願買電動車的人還是少數。

    一直以來困擾電動車發展的兩大難題是充電速度和續航里程,前者的話,蔚來已經提出了換電服務,這算是頗為便捷的一個解決方式;後者的話,經過這幾年的發展,不少電動車的理論續航里程都能達到450km以上,未來我相信能持續增多。

    我曾經駕駛過特斯拉,無可否認,那種一點就有的加速確實不錯。但沒有了引擎和排氣的聲音,感覺整個駕駛參与度不夠高,就像關了聲音看恐怖片般索然無味。這也不是無法彌補,現在有不少汽車都有聲浪彌補功能,可根據駕駛員踩踏油門的深度來模擬出引擎和排氣的聲音,但假的真不了。

    總結

    這幾個汽車的變化,到底是好還是壞,不同的人有不同的看法。這些轉變就像青春期的愛情變為工作后的愛情,前者是單純懵懂的,後者則是現實清晰的。更為關鍵的是,汽車和愛情都是不可逆轉的,而我們唯一能做的就是珍惜和享受眼前的汽車生活。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

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

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

    最低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/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 教授試了一款不到10萬的智能SUV?

    教授試了一款不到10萬的智能SUV?

    1英寸的中控大屏清晰度和靈敏度都表現不錯,並且還加入了車聯網功能,通過語音可以控制車輛大多數的功能,例如開關天窗,開關音樂等,方便車主日常用車生活,同時增加行車安全。整車的配置豐富,前排座椅加熱,車道偏離預警,盲區監測,全景攝像頭,ESp車身穩定系統應有盡有,這也是自主品牌的優勢之一。

    五月份的青島是夏至未至的時分,海風輕拂過臉頰,聞着少許帶有魚腥味的海風,來到青島試駕2018款凱翼X3,雖然說凱翼是新興品牌,但並不代表車輛的競爭力低,到底細節如何?產品力怎麼樣?為你一一解讀。

    外觀上,2018款凱翼X3與2017款區別不大,U型鍍鉻條圍繞着進去格柵,並與前大燈相結合,配合上半圓形行車燈圍繞的透鏡大燈,雖說是鹵素光源,但透鏡的加入讓整車的精神氣更上一層樓。

    雙色的輪圈時尚感很強,215/60 R17的輪胎尺寸,有足夠厚的胎壁來面對各種複雜路況,符合它SUV的定位,高配車型為18寸輪圈,視覺效果更好,但濾震效果不及17寸輪胎。

    車尾的造型是凱翼X3的亮點之一,小書包造型的外掛備胎,讓整輛車的野性十足,側開的開門方式也個性十足;尾燈的造型與頭燈呼應,同是半圓形,點亮后視覺效果滿分。

    內飾有兩種配色:全黑/黑棕,中控台總體以對稱設計為主,主要突出年輕,簡約化,中控台上方使用的是軟質材料,銀色的飾條讓整个中控台的層次感增加了不少,圓形的空調出風口加上周圍的銀色裝飾,增添了內飾的一絲活力。10.1英寸的中控大屏清晰度和靈敏度都表現不錯,並且還加入了車聯網功能,通過語音可以控制車輛大多數的功能,例如開關天窗,開關音樂等,方便車主日常用車生活,同時增加行車安全。

    整車的配置豐富,前排座椅加熱,車道偏離預警,盲區監測,全景攝像頭,ESp車身穩定系統應有盡有,這也是自主品牌的優勢之一。

    主駕的座椅支持6向手動調節,座椅皮質的手感雖然不算特別好,比上不足比下有餘。第二排座椅支持4/6放倒,不過放倒以後上下地台差別大,不利於大物件裝載,側開門也帶來了一個缺點,往右開的側開門方式不太適合中國國情使用,因為我國道路是靠右行駛,一般情況下是靠右停車,向右開門的話會阻礙物品的裝載以及影響安全。

    2018款凱翼X3全系標配1.6L自然吸氣發動機,智享版以上配備CVT變速箱(智享版一下為手動),發動機最大馬力126ps,最大扭矩160N*m,從數據上看,整體的功率不算大,由於CVT變速箱的特性,整體動力輸出以平順為主調,2000rpm一下車輛表現慵懶,2000rpm以上稍有起色,如果想要在高速上快速超車,需要增加多一點提前量。3000rpm以上發動機的噪音又會相對明顯,總體來說動力總成在夠用的範圍。

    方向盤轉向力度有三擋可調,轉向有三種重量,日常使用個人比較喜歡最輕模式,減輕勞動強度。

    凱翼X3使用前麥弗遜后雙連桿結構,整體調校毫無意外地偏舒適,在車輛經過減速帶等快速的凸起時,會比較积極地過濾震動,但遇到波浪型或較大拋跳的路面時,懸挂就顯得有點無所適從,且懸挂偏向支撐,所以傳到車內的震動會相對大一點,給人一絲運動感。

    總結

    凱翼X3的外形和內飾都是為了迎接年輕人圍目的,2018款凱翼X3將該理念貫徹得更加徹底,並且增加了車聯網系統,進入如今時髦的互聯網汽車行列,即使將價格控制在10萬以下,ESp、盲區監測、車道偏離預警系統等實用的配置一樣不落,動力和操控不是凱翼的長處,但好在空間濾震都不錯,總體中規中矩,沒有什麼短板,是年輕人第一輛車,又需要一定實用性不錯的選擇。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

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

    復聯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座車都這麼給力,買誰好?

    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萬起的車值不值?

    近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行銷專家,教你從零開始的技巧

  • mingw32 exception在sjlj與dwarf差別-反彙編分析

    mingw32 exception在sjlj與dwarf差別-反彙編分析

    sjlj (setjump/longjump)與dwarf-2為mingw32兩種異常處理模型的實現。sjlj有着開銷,而隨linux發行的mingw32開發庫包都是用sjlj版編譯的,而Qt卻採用dwarf-2版,那麼兩者之間有多少差異,本文就這問題對兩版的異常代碼的反彙編進行分析比較。

    我使用mingw-w65-i686-810的sjlj與dwarf-2兩個版本對下面異常代碼編譯。

    __attribute__((dllimport)) int dllfunc();
    int main()
    {
        dllfunc();
        //_create_locale(LC_ALL, "C");
        printf("abc");
        //return 0;
    
        try
        {
            try
            {
                throw std::exception();
            }
            catch(std::exception&)
          {
                std::rethrow_exception(std::current_exception());
          }
            
        }
        catch(int)
        {
            
        }
        catch(std::exception& e)
        {
            std::cout << e.what() << std::endl;
        }
        catch(...)
        {
            std::cout << "unknown" << std::endl;
        }
        return 0;
    }

    代碼邏輯:

    兩層 try/catch,

    1. 裡層 try/catch

    1.1 try塊, throw 異常

    1.2 catch塊, rethrow

    2. 外層 try/catch

    2.1 有三catch分支。

     

    開刷前,先定義一下。

    如果將 try/catch 去除 c++語言特性后,基本就是一種由c++庫還有c++編譯器共同管理的 goto。

    throw相當於goto, catch相當於label(一種以類型區分的)。

    那麼c++編譯器與c++庫為我們提供了什麼樣的管理呢?

    c++編譯器

    0. 利用c++支持對象析構進行try塊保護。

    1. 將 throw 關鍵字生成彙編 call __cxa_throw,調用 c++庫的函數。

    2. 為每個catch塊生成代碼片斷,只能通過jmp跳轉進來。

    2.1 開頭 call __cxa_begin_catch。

    2.2 結尾 call __cxa_end_catch。

    2.3 最後跳出到 try/catch塊邏輯代碼的下條執行指令。

    3. 為同一try/catch塊的所有catch塊產生分支控制代碼。

    4. 為try塊的析構代碼產生跳轉入口。

    5. 為每一層try/catch塊生成 uncaught 代碼塊,調用 _Unwind_Resume。

    c++庫:

    1. __cxa_throw,馬上_Unwind_RaiseException。跳轉到當前最裏面一層 try/catch的支路控制代碼片斷。

    2. _Unwind_Resume,向上繼續展開。

    3. std::rethrow_exception,調用 __gcclibcxx_demangle_callback,

    3.1 要麼有 catch可達跳回到原來代碼的控制流,直接離開std::rethrow_exception的調用上下文。

    3.2 要麼從__gcclibcxx_demangle_callback返回,執行terminate結束進程。

     

    sjlj 版的反彙編代碼比 dwarf-2 版的多了50行。

    先來看dwarf-2的反彙編代碼 

      1  <+0>:    lea    0x4(%esp),%ecx
      2  <+4>:    and    $0xfffffff0,%esp
      3  <+7>:    pushl  -0x4(%ecx)
      4  <+10>:    push   %ebp
      5  <+11>:    mov    %esp,%ebp
      6  <+13>:    push   %esi
      7  <+14>:    push   %ebx
      8  <+15>:    push   %ecx
      9  <+16>:    sub    $0x2c,%esp
     10  <+19>:    call   0x401890 <__main>
     11  <+24>:    mov    0x4071a4,%eax
     12  <+29>:    call   *%eax
     13  <+31>:    movl   $0x404045,(%esp)
     14  <+38>:    call   0x4027c4 <printf>
     15  <+43>:    movl   $0x4,(%esp)
     16  <+50>:    call   0x4017ac <__cxa_allocate_exception>
     17  <+55>:    mov    %eax,%ebx
     18  <+57>:    mov    %ebx,%ecx
     19  <+59>:    call   0x402890 <std::exception::exception()>
     20  <+64>:    movl   $0x4017d4,0x8(%esp)
     21  <+72>:    movl   $0x4042a8,0x4(%esp)
     22  <+80>:    mov    %ebx,(%esp)
     23  <+83>:    call   0x401794 <__cxa_throw>
     24  <+88>:    mov    $0x0,%eax
     25  <+93>:    jmp    0x401723 <main()+355>
     26  <+98>:    mov    %edx,%ecx
     27  <+100>:    cmp    $0x2,%ecx
     28  <+103>:    je     0x40162b <main()+107>
     29  <+105>:    jmp    0x401663 <main()+163>
     30  <+107>:    mov    %eax,(%esp)
     31  <+110>:    call   0x4017a4 <__cxa_begin_catch>
     32  <+115>:    mov    %eax,-0x1c(%ebp)
     33  <+118>:    lea    -0x28(%ebp),%eax
     34  <+121>:    mov    %eax,(%esp)
     35  <+124>:    call   0x4017cc <_ZSt17current_exceptionv>
     36  <+129>:    lea    -0x28(%ebp),%eax
     37  <+132>:    mov    %eax,(%esp)
     38  <+135>:    call   0x4017c4 <_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE>
     39  <+140>:    mov    %eax,%esi
     40  <+142>:    mov    %edx,%ebx
     41  <+144>:    lea    -0x28(%ebp),%eax
     42  <+147>:    mov    %eax,%ecx
     43  <+149>:    call   0x4017ec <_ZNSt15__exception_ptr13exception_ptrD1Ev>
     44  <+154>:    call   0x40179c <__cxa_end_catch>
     45  <+159>:    mov    %esi,%eax
     46  <+161>:    mov    %ebx,%edx
     47  <+163>:    cmp    $0x1,%edx
     48  <+166>:    je     0x40166f <main()+175>
     49  <+168>:    cmp    $0x2,%edx
     50  <+171>:    je     0x401683 <main()+195>
     51  <+173>:    jmp    0x4016ca <main()+266>
     52  <+175>:    mov    %eax,(%esp)
     53  <+178>:    call   0x4017a4 <__cxa_begin_catch>
     54  <+183>:    mov    (%eax),%eax
     55  <+185>:    mov    %eax,-0x24(%ebp)
     56  <+188>:    call   0x40179c <__cxa_end_catch>
     57  <+193>:    jmp    0x401618 <main()+88>
     58  <+195>:    mov    %eax,(%esp)
     59  <+198>:    call   0x4017a4 <__cxa_begin_catch>
     60  <+203>:    mov    %eax,-0x20(%ebp)
     61  <+206>:    mov    -0x20(%ebp),%eax
     62  <+209>:    mov    (%eax),%eax
     63  <+211>:    add    $0x8,%eax
     64  <+214>:    mov    (%eax),%eax
     65  <+216>:    mov    -0x20(%ebp),%edx
     66  <+219>:    mov    %edx,%ecx
     67  <+221>:    call   *%eax
     68  <+223>:    mov    %eax,0x4(%esp)
     69  <+227>:    movl   $0x6ff07a00,(%esp)
     70  <+234>:    call   0x4017b4 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
     71  <+239>:    movl   $0x4017bc,(%esp)
     72  <+246>:    mov    %eax,%ecx
     73  <+248>:    call   0x4017f4 <_ZNSolsEPFRSoS_E>
     74  <+253>:    sub    $0x4,%esp
     75  <+256>:    call   0x40179c <__cxa_end_catch>
     76  <+261>:    jmp    0x401618 <main()+88>
     77  <+266>:    mov    %eax,(%esp)
     78  <+269>:    call   0x4017a4 <__cxa_begin_catch>
     79  <+274>:    movl   $0x404049,0x4(%esp)
     80  <+282>:    movl   $0x6ff07a00,(%esp)
     81  <+289>:    call   0x4017b4 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
     82  <+294>:    movl   $0x4017bc,(%esp)
     83  <+301>:    mov    %eax,%ecx
     84  <+303>:    call   0x4017f4 <_ZNSolsEPFRSoS_E>
     85  <+308>:    sub    $0x4,%esp
     86  <+311>:    call   0x40179c <__cxa_end_catch>
     87  <+316>:    jmp    0x401618 <main()+88>
     88  <+321>:    mov    %eax,%ebx
     89  <+323>:    call   0x40179c <__cxa_end_catch>
     90  <+328>:    mov    %ebx,%eax
     91  <+330>:    mov    %eax,(%esp)
     92  <+333>:    call   0x402770 <_Unwind_Resume>
     93  <+338>:    mov    %eax,%ebx
     94  <+340>:    call   0x40179c <__cxa_end_catch>
     95  <+345>:    mov    %ebx,%eax
     96  <+347>:    mov    %eax,(%esp)
     97  <+350>:    call   0x402770 <_Unwind_Resume>
     98  <+355>:    lea    -0xc(%ebp),%esp
     99  <+358>:    pop    %ecx
    100  <+359>:    pop    %ebx
    101  <+360>:    pop    %esi
    102  <+361>:    pop    %ebp
    103  <+362>:    lea    -0x4(%ecx),%esp
    104  <+365>:    ret    

    我們的主要代碼邏輯只有20-30條指令

     

     當 throw時,__cxa_throw函數是不會返回的, 如同goto最後是跳轉到他處,若被本層catch處理完才會跳轉回來<+88>。

    然後看c++編譯器為我們生成的異常代碼 。

     

     

     

     

     

     對於沒有發生異常時,代碼執行路徑基本不會去涉及到異常代碼支路,開銷幾近為0,只是代碼量增大。

    下面來看 sjlj 版的彙編代碼,

      1 function main():
      2  <+0>:    lea    0x4(%esp),%ecx
      3  <+4>:    and    $0xfffffff0,%esp
      4  <+7>:    pushl  -0x4(%ecx)
      5  <+10>:    push   %ebp
      6  <+11>:    mov    %esp,%ebp
      7  <+13>:    push   %edi
      8  <+14>:    push   %esi
      9  <+15>:    push   %ebx
     10  <+16>:    push   %ecx
     11  <+17>:    sub    $0x68,%esp
     12  <+20>:    movl   $0x4017ac,-0x44(%ebp)
     13  <+27>:    movl   $0x402958,-0x40(%ebp)
     14  <+34>:    lea    -0x3c(%ebp),%eax
     15  <+37>:    lea    -0x18(%ebp),%ebx
     16  <+40>:    mov    %ebx,(%eax)
     17  <+42>:    mov    $0x4015b4,%edx
     18  <+47>:    mov    %edx,0x4(%eax)
     19  <+50>:    mov    %esp,0x8(%eax)
     20  <+53>:    lea    -0x5c(%ebp),%eax
     21  <+56>:    mov    %eax,(%esp)
     22  <+59>:    call   0x402790 <_Unwind_SjLj_Register>
     23  <+64>:    call   0x4018b0 <__main>
     24  <+69>:    mov    0x406194,%eax
     25  <+74>:    movl   $0xffffffff,-0x58(%ebp)
     26  <+81>:    call   *%eax
     27  <+83>:    movl   $0x404001,(%esp)
     28  <+90>:    call   0x4027e4 <printf>
     29  <+95>:    movl   $0x4,(%esp)
     30  <+102>:    call   0x4017cc <__cxa_allocate_exception>
     31  <+107>:    mov    %eax,-0x60(%ebp)
     32  <+110>:    mov    %eax,%ecx
     33  <+112>:    call   0x4028b0 <std::exception::exception()>
     34  <+117>:    movl   $0x4017f4,0x8(%esp)
     35  <+125>:    movl   $0x404264,0x4(%esp)
     36  <+133>:    mov    -0x60(%ebp),%eax
     37  <+136>:    mov    %eax,(%esp)
     38  <+139>:    movl   $0x1,-0x58(%ebp)
     39  <+146>:    call   0x4017b4 <__cxa_throw>
     40  <+151>:    mov    $0x0,%eax
     41  <+156>:    mov    %eax,-0x60(%ebp)
     42  <+159>:    jmp    0x401733 <main()+547>
     43  <+164>:    lea    0x18(%ebp),%ebp
     44  <+167>:    mov    -0x54(%ebp),%edx
     45  <+170>:    mov    -0x50(%ebp),%ecx
     46  <+173>:    mov    -0x58(%ebp),%eax
     47  <+176>:    test   %eax,%eax
     48  <+178>:    je     0x4015e6 <main()+214>
     49  <+180>:    sub    $0x1,%eax
     50  <+183>:    test   %eax,%eax
     51  <+185>:    je     0x40161b <main()+267>
     52  <+187>:    sub    $0x1,%eax
     53  <+190>:    test   %eax,%eax
     54  <+192>:    je     0x4016f8 <main()+488>
     55  <+198>:    sub    $0x1,%eax
     56  <+201>:    test   %eax,%eax
     57  <+203>:    je     0x401712 <main()+514>
     58  <+209>:    sub    $0x1,%eax
     59  <+212>:    ud2    
     60  <+214>:    mov    %edx,%eax
     61  <+216>:    mov    %ecx,%edx
     62  <+218>:    mov    %edx,%ecx
     63  <+220>:    cmp    $0x2,%ecx
     64  <+223>:    je     0x4015f3 <main()+227>
     65  <+225>:    jmp    0x401642 <main()+306>
     66  <+227>:    mov    %eax,(%esp)
     67  <+230>:    call   0x4017c4 <__cxa_begin_catch>
     68  <+235>:    mov    %eax,-0x1c(%ebp)
     69  <+238>:    lea    -0x28(%ebp),%eax
     70  <+241>:    mov    %eax,(%esp)
     71  <+244>:    call   0x4017ec <_ZSt17current_exceptionv>
     72  <+249>:    lea    -0x28(%ebp),%eax
     73  <+252>:    mov    %eax,(%esp)
     74  <+255>:    movl   $0x2,-0x58(%ebp)
     75  <+262>:    call   0x4017e4 <_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE>
     76  <+267>:    mov    %edx,-0x60(%ebp)
     77  <+270>:    mov    %ecx,-0x64(%ebp)
     78  <+273>:    lea    -0x28(%ebp),%eax
     79  <+276>:    mov    %eax,%ecx
     80  <+278>:    call   0x40180c <_ZNSt15__exception_ptr13exception_ptrD1Ev>
     81  <+283>:    mov    -0x60(%ebp),%eax
     82  <+286>:    mov    %eax,-0x60(%ebp)
     83  <+289>:    mov    -0x64(%ebp),%esi
     84  <+292>:    mov    %esi,-0x64(%ebp)
     85  <+295>:    call   0x4017bc <__cxa_end_catch>
     86  <+300>:    mov    -0x60(%ebp),%eax
     87  <+303>:    mov    -0x64(%ebp),%edx
     88  <+306>:    cmp    $0x1,%edx
     89  <+309>:    je     0x40164e <main()+318>
     90  <+311>:    cmp    $0x2,%edx
     91  <+314>:    je     0x401665 <main()+341>
     92  <+316>:    jmp    0x4016b3 <main()+419>
     93  <+318>:    mov    %eax,(%esp)
     94  <+321>:    call   0x4017c4 <__cxa_begin_catch>
     95  <+326>:    mov    (%eax),%eax
     96  <+328>:    mov    %eax,-0x20(%ebp)
     97  <+331>:    call   0x4017bc <__cxa_end_catch>
     98  <+336>:    jmp    0x4015a7 <main()+151>
     99  <+341>:    mov    %eax,(%esp)
    100  <+344>:    call   0x4017c4 <__cxa_begin_catch>
    101  <+349>:    mov    %eax,-0x24(%ebp)
    102  <+352>:    mov    -0x24(%ebp),%eax
    103  <+355>:    mov    (%eax),%eax
    104  <+357>:    add    $0x8,%eax
    105  <+360>:    mov    (%eax),%eax
    106  <+362>:    mov    -0x24(%ebp),%edx
    107  <+365>:    mov    %edx,%ecx
    108  <+367>:    call   *%eax
    109  <+369>:    mov    %eax,0x4(%esp)
    110  <+373>:    movl   $0x6ff29a00,(%esp)
    111  <+380>:    movl   $0x3,-0x58(%ebp)
    112  <+387>:    call   0x4017d4 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
    113  <+392>:    movl   $0x4017dc,(%esp)
    114  <+399>:    mov    %eax,%ecx
    115  <+401>:    call   0x401814 <_ZNSolsEPFRSoS_E>
    116  <+406>:    sub    $0x4,%esp
    117  <+409>:    call   0x4017bc <__cxa_end_catch>
    118  <+414>:    jmp    0x4015a7 <main()+151>
    119  <+419>:    mov    %eax,(%esp)
    120  <+422>:    call   0x4017c4 <__cxa_begin_catch>
    121  <+427>:    movl   $0x404005,0x4(%esp)
    122  <+435>:    movl   $0x6ff29a00,(%esp)
    123  <+442>:    movl   $0x4,-0x58(%ebp)
    124  <+449>:    call   0x4017d4 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
    125  <+454>:    movl   $0x4017dc,(%esp)
    126  <+461>:    mov    %eax,%ecx
    127  <+463>:    call   0x401814 <_ZNSolsEPFRSoS_E>
    128  <+468>:    sub    $0x4,%esp
    129  <+471>:    movl   $0xffffffff,-0x58(%ebp)
    130  <+478>:    call   0x4017bc <__cxa_end_catch>
    131  <+483>:    jmp    0x4015a7 <main()+151>
    132  <+488>:    mov    %edx,-0x60(%ebp)
    133  <+491>:    call   0x4017bc <__cxa_end_catch>
    134  <+496>:    mov    -0x60(%ebp),%eax
    135  <+499>:    mov    %eax,(%esp)
    136  <+502>:    movl   $0xffffffff,-0x58(%ebp)
    137  <+509>:    call   0x402788 <_Unwind_SjLj_Resume>
    138  <+514>:    mov    %edx,-0x60(%ebp)
    139  <+517>:    movl   $0x0,-0x58(%ebp)
    140  <+524>:    call   0x4017bc <__cxa_end_catch>
    141  <+529>:    mov    -0x60(%ebp),%eax
    142  <+532>:    mov    %eax,(%esp)
    143  <+535>:    movl   $0xffffffff,-0x58(%ebp)
    144  <+542>:    call   0x402788 <_Unwind_SjLj_Resume>
    145  <+547>:    lea    -0x5c(%ebp),%eax
    146  <+550>:    mov    %eax,(%esp)
    147  <+553>:    call   0x402780 <_Unwind_SjLj_Unregister>
    148  <+558>:    mov    -0x60(%ebp),%eax
    149  <+561>:    lea    -0x10(%ebp),%esp
    150  <+564>:    pop    %ecx
    151  <+565>:    pop    %ebx
    152  <+566>:    pop    %esi
    153  <+567>:    pop    %edi
    154  <+568>:    pop    %ebp
    155  <+569>:    lea    -0x4(%ecx),%esp
    156  <+572>:    ret    

    下面的分析只列出不同的地方 

     上圖的註釋有誤沒有勘誤過,lea是不訪問內存,通常代替add指令做加法,應該是6條指令要訪問內存。

    支路控制代碼:

     

     

     

     

     可以看出,支路選路控制指令多而且複雜,還有就是跳轉多。

    最後是函數結束前。

     

     

     

     可以看出在 sjlj 版本中,即使代碼不發生異常,函數在進入與離開時都要為登記維護付出一此成本,當涉及異常代碼時,支路選路控制更加複雜更多跳轉。這裡有一個成本比例,你的函數邏輯簡單,上面的開銷比重就越大,如果是頻繁調用的輕量函數就要考慮不用exception這樣的error handle。

    還有就是當發生異常時,需要交給c++庫去管理,不同異常處理模型的實現,有着不同的開銷,本文並沒有涉及到。只是單純從c++庫以外的代碼進行分析,也足夠看出他們之間有着一定的差別。

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

    【其他文章推薦】

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

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

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

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

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

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

  • [源碼解析] 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 使用問題匯總

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案