視頻處理之OSD

欲觀原文,請君移步

OSD簡介

OSD,on-screen display的簡稱,即屏幕菜單式調節方式。一般我們按一下Menu鍵后屏幕彈出的显示器各項調節項目信息的矩形菜單,比如調亮度,色調,飽和度等信息,這個显示這個菜單的功能就是視頻行業的OSD。

基於FPGA的OSD設計與實現

1 Xilinx OSD IP功能

  • 支持最多8個layer
  • 背景顏色可編程
  • 位置,大小,顏色,透明度(alpha)可編程
  • 支持RGB和YUV視頻流

2 硬件結構框圖

硬件平台是基於xilinx xc7z035芯片開發的,關鍵模塊框圖如下圖1所示。

  • 一個時序產生模塊Video Timing Controller(在本次實驗中採用1080P標準時序)

  • 首先PL端將視頻流通過VDMA讀出,輸出接口為AXI4-Stream的數據流

  • 然後視頻流進入OSD IP(OSD輸入輸出也是AXI4-Stream接口)

  • 最後OSD輸出數據流與1080P時序同時送入到AXI4-Stream to Video Out模塊,輸出為HDMI接口

下面小編會詳細介紹OSD IP的例化與使用

3 OSD PL端

如果在使用OSD IP過程中出現如下錯誤,請在xilinx官網上申請OSD的License,這裏不再詳述如何申請License。

首先在Block Design中加入Video On Screen Display,打開後會看到如下圖2。

(1) 勾選AXI-Lite Interface:PS端通過AXI-Lite進行配置該IP

(2) Video Format選擇RGB

(3) Layers選擇2

(4) Layer Configuration:LAYER0選擇外部視頻流,也就是實時視頻,LAYER1選擇Internal,PS端可以控制進行圖文疊加

點擊Screen Layout Options,如圖3所示

(1) Background size(選擇背景大小)里寬度輸入1920,高度輸入1080

(2) Background color輸入背景顏色,這裏選擇黑色,可以通過axi-lite來控制

(3) layer0因為選擇的是外部視頻流,所以比如設置為外部視頻流分辨率,輸錯了,可能無法正常使用,小編已經遇到過了,本文使用1920×1080外部視頻流

(4) layer1因為選擇的是內部圖像控制器,所以無所謂設置什麼,可以通過axi-lite控制,所以選擇默認即可

點擊LAYER 1 Options出現圖4界面:因為是內部圖像控制器,所以可以進行一些配置,比如顏色多少,字符數目,比特像素等等,這裏小編選擇的是默認。

配置完OSD IP后,將其AXI-lite掛在總線上即可,然後保存Block Design即可。

注:點開Address Editor,一定要確定該IP被分配地址空間,如果沒有,點擊一下自動分配(小編遇到的問題就是這個ip地址空間在unmap里,導致後續PS端OSD IP無法初始化)。

4 OSD PS端

下面就是常規操作include bitstream導出SDK,其實就是生成hdf文件,硬件信息。然後就launch SDk。如圖4所示,可以看到hdf文件里都有什麼。

新建一個design_top的空工程,如圖5所示,在design_top_bsp下面可以看到system.mss文件,在紅框中找到OSD IP。

點擊import examples,出現如圖6所示,勾選對話框后選擇OK(不會玩IP先整個example)。

打開XosdSelfTestExample.c即可看到該例子程序是怎麼個處理流程(圖7為main函數,圖8為使用流程)小編稱之為PS端IP使用三步法

  • 第一步先進行lookup該IP

  • 第二步就是初始化該IP

  • 第三步就是使用IP

運行一下,結果如圖9所示,可以看到UART會打印OSD成功信息。

OSD 實例

閑話不說,上面經過了OSD example,小編也作為一個PS端初學者來玩一玩。

尷尬的是經常在寫c代碼的時候想着寫begin…end,真是verilog寫習慣了,思想難以改變,原來是花括弧啊{}

初始化模塊如下

在初始化后必須將該模塊進行複位,然後,否則該IP啟動不了。

int OsdInit(int DeviceID)
{
	int Status;
	/* Initialize the OSD instance */
	OsdCfgPtr = XOSD_LookupConfig(DeviceID);
	Status = XOSD_CfgInitialize(&Osd, OsdCfgPtr,OsdCfgPtr->BaseAddress);
	if (Status != XST_SUCCESS)		return 1;
	/* Reset the devices */
	XOSD_Reset(&Osd);
	/* Enable the OSD device and tell it to pick up the register changes	*/
	XOSD_Enable(&Osd);
	XOSD_RegUpdateEnable(&Osd);
	return 0;
}

配置模塊

這裏需要注意的是把BANKIndex輸入為1,否則會進行字符填寫方式就需要改變,不符合操作習慣XOSD_LoadCharacterSetBank(&Osd, Gcindex, 1, (u32 *)Font);

void Graphics_setting(u8 Gcindex,u8 LayerPriority,u32 ColorData[],u32 *TextData)
{
	int width = 1920;
	int height = 1080;
	int LayerAlphaValue = 0xFF;
	int LayerGlobalAlphaEnable = 0;
	XOSD_SetLayerAlpha(&Osd, Gcindex, LayerGlobalAlphaEnable,LayerAlphaValue);
	XOSD_SetLayerPriority(&Osd, Gcindex, LayerPriority);
	XOSD_SetLayerDimension(&Osd, Gcindex, 0, 0, width, height);
	XOSD_EnableLayer(&Osd, Gcindex);
	/* Load color, font and text and set the active banks */
	XOSD_LoadColorLUTBank(&Osd, Gcindex, 0, ColorData);
	//set BankIndex is 1(fit our keyboard)
	XOSD_LoadCharacterSetBank(&Osd, Gcindex, 1, (u32 *)Font);
	XOSD_LoadTextBank(&Osd, Gcindex, 0, (u32 *)TextData);
	XOSD_SetActiveBank(&Osd, Gcindex, 0, 0, 0, 0);
}

圖文疊加模塊

void OsdDrawText(int Gcindex,int x_pos, int y_pos, int color, int string_index, int text_size)
{
	u32 Instruction[XOSD_INS_SIZE];
	u16 ObjType = XOSD_INS_OPCODE_BOXTXT; /* A text string 	XOSD_INS_OPCODE_TXT*/
	u8 ObjSize = (text_size<<4); /* Text Scale factor (1x, 2x, 4x, 8x)	*/
	u16 XStart = x_pos; /* Horizontal start pixel of the text	*/
	u16 YStart = y_pos; /* Vertical start line of the text */
	u16 XEnd = x_pos; /* Horizontal end pixel of the text (not	used) */
	u16 YEnd = y_pos; /* Vertical end line of the text (must be same as YStart) */
	u8 TextIndex = string_index; /* Index of Text String */
	u8 ColorIndex = color; /* Color used to draw text */


	XOSD_CreateInstruction(&Osd, Instruction, Gcindex,ObjType, ObjSize,	XStart, YStart, XEnd, YEnd,TextIndex, ColorIndex);
	XOSD_LoadInstructionList(&Osd, Gcindex, 0, Instruction, 1);
	return;
}

實現結果

前面只給出了兩個圖層,工程退不回去了,目前工程實現的是疊加8個圖層(1個視頻,7個內部圖像控制器)。

參考鏈接

百度網盤源碼以及參考文檔鏈接如下

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準

Python 圖像處理 OpenCV (6):圖像的閾值處理

前文傳送門:

「Python 圖像處理 OpenCV (1):入門」

「Python 圖像處理 OpenCV (2):像素處理與 Numpy 操作以及 Matplotlib 显示圖像」

「Python 圖像處理 OpenCV (3):圖像屬性、圖像感興趣 ROI 區域及通道處理」

「Python 圖像處理 OpenCV (4):圖像算數運算以及修改顏色空間」

「Python 圖像處理 OpenCV (5):圖像的幾何變換」

圖像的閾值

看到這個詞可能大家都很懵,為啥在圖像處理裏面還會有閾值。

圖像的閾值處理用大白話講就是將圖像轉化為二值圖像(黑白圖),目的是用來提取圖像中的目標物體,將背景和噪聲區分開(可以近似的認為除了目標全是噪聲)。

通常會設定一個閾值 T ,通過 T 將圖像的像素劃分為兩類:大於 T 的像素群和小於 T 的像素群。

首先可以先將圖像轉化為灰度圖像,因為在灰度圖像中,每個像素都只有一個灰度值用來表示當前像素的亮度。

接下來二值化處理可以將圖像中的像素劃分為兩類顏色,一種是大於閾值 T 的,另一種是小於閾值 T 的。

比如最常見的二值圖像:

當灰度值小於閾值 T 的時候,可以將其像素設置為 0 ,表示為黑色。

當灰度值大於閾值 T 的時候,可以將其像素設置為 255 ,表示為白色。

在 OpenCV 中,為我們提供了閾值函數 threshold() 來幫助我們實現二值圖像的處理。

函數如下:

retval, dst = threshold(src, thresh, maxval, type, dst=None)
  • retval: 閾值
  • dst: 處理后的圖像
  • src: 原圖像
  • thresh: 閾值
  • maxval: 最大值
  • type: 處理類型

常用的 5 中處理類型如下:

  • cv.THRESH_BINARY: 二值處理
  • cv.THRESH_BINARY_INV: 反二值處理
  • cv.THRESH_TRUNC: 截斷閾值化
  • cv.THRESH_TOZERO: 閾值化為 0
  • cv.THRESH_TOZERO_INV: 反閾值化為 0

接下來這幾種處理類型有啥不同,我們一個一個來看。

二值處理

這種二值處理方式最開始需要選定一個閾值 T ,從 0 ~ 255 之間,我這裏選擇出於中間的那個數 127 。

接下來的處理規則就是這樣的:

  • 大於等於 127 的像素點的灰度值設定為最大值,也就是 255 白色
  • 小於 127 的像素點的灰度值設定為 0 ,也就是黑色

接下來開始寫代碼,看我們的馬里奧同學(不知道你們還記不記得我們的馬里奧同學):

import cv2 as cv

src = cv.imread("maliao.jpg")

# BGR 圖像轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

# 二值圖像處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)

# 显示圖像
cv.imshow("src", src)
cv.imshow("result", b)

# 等待显示
cv.waitKey(0)
cv.destroyAllWindows()

反二值處理

這種方式和上面的二值處理非常相似,只是把處理規則給反了一下:

  • 大於等於 127 的像素點的灰度值設定為 0 ,也就是白色
  • 小於 127 的像素點的灰度值設定為最大值,也就是 255 白色

完整代碼如下:

import cv2 as cv

src = cv.imread("maliao.jpg")

# BGR 圖像轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

# 二值圖像處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)

# 显示圖像
cv.imshow("src", src)
cv.imshow("result", b)

# 等待显示
cv.waitKey(0)
cv.destroyAllWindows()

從圖像上可以看到,顏色和上面的二值圖像正好相反,大部分的位置都變成了白色。

截斷閾值化

這種方法還是需要先選定一個閾值 T ,圖像中大於該閾值的像素點被設定為該閾值,小於該閾值的保持不變。

完整代碼如下:

import cv2 as cv

src = cv.imread("maliao.jpg")

# BGR 圖像轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

# 二值圖像處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)

# 显示圖像
cv.imshow("src", src)
cv.imshow("result", b)

# 等待显示
cv.waitKey(0)
cv.destroyAllWindows()

這種方式實際上是把圖片比較亮的像素處理成為閾值,其他部分保持不變。

閾值化為 0

這種方式還是需要先選定一個閾值 T ,將小於 T 的像素點設置為 0 黑色,其他的保持不變。

完整代碼如下:

import cv2 as cv

src = cv.imread("maliao.jpg")

# BGR 圖像轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

# 二值圖像處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)

# 显示圖像
cv.imshow("src", src)
cv.imshow("result", b)

# 等待显示
cv.waitKey(0)
cv.destroyAllWindows()

這個方法是亮的部分不改,把比較暗的部分修改為 0 。

反閾值化為 0

這個和前面的反二值圖像很像,同樣是反閾值化為 0 ,將大於等於 T 的像素點變為 0 ,其餘保持不變。

完整代碼如下:

import cv2 as cv

src = cv.imread("maliao.jpg")

# BGR 圖像轉灰度
gray_img = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

# 二值圖像處理
r, b = cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)

# 显示圖像
cv.imshow("src", src)
cv.imshow("result", b)

# 等待显示
cv.waitKey(0)
cv.destroyAllWindows()

這個方法是暗的部分不改,把比較亮的部分修改為 0 。

全家福

接下來還是給這幾種閾值處理后的圖像來個全家福,讓大家能有一個直觀的感受,代碼我也給出來,如下:

import cv2 as cv
import matplotlib.pyplot as plt

# 讀取圖像
img=cv.imread('maliao.jpg')
lenna_img = cv.cvtColor(img,cv.COLOR_BGR2RGB)
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)

# 閾值化處理
ret1, thresh1=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY)
ret2, thresh2=cv.threshold(gray_img, 127, 255, cv.THRESH_BINARY_INV)
ret3, thresh3=cv.threshold(gray_img, 127, 255, cv.THRESH_TRUNC)
ret4, thresh4=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO)
ret5, thresh5=cv.threshold(gray_img, 127, 255, cv.THRESH_TOZERO_INV)

# 显示結果
titles = ['Gray Img','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [gray_img, thresh1, thresh2, thresh3, thresh4, thresh5]

# matplotlib 繪圖
for i in range(6):
   plt.subplot(2, 3, i+1), plt.imshow(images[i],'gray')
   plt.title(titles[i])
   plt.xticks([]),plt.yticks([])

plt.show()

示例代碼

如果有需要獲取源碼的同學可以在公眾號回復「OpenCV」進行獲取。

參考

https://blog.csdn.net/Eastmount/article/details/83548652

http://www.woshicver.com/

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

【其他文章推薦】

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

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

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

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

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

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

※回頭車貨運收費標準

一名優秀的程序員應該向誰提問

這兩年來,向我提問的人真的可以稱得上是不計其數了。哎呀,一不小心又用了個成語,裝逼在無形當中啊。雖然有點誇張,但說真的不算少了,請摸着良心問問,你是不是就問過?

但我特別討厭一種行為,就是用手機拍電腦屏幕的照片來提問。為什麼這麼說呢?請你立刻現在馬上拿起手機自己拍張照試試。如果相機不給力,屏幕像素又低,我的天吶,看這種照片上的代碼真的是痛苦啊!

鑒於此,我在群里三番五次提醒過,請用截屏,不要用手機拍照!但隔三差五還是有人這樣照干不誤,我很生氣,真的。

你提問,肯定想要得到回答,對吧?如果你用心,那回答的人也就會用心,即便是你的問題石沉大海了,那也是對自己的一種負責任啊。

在提問題的時候,你應該做好充分的準備:

  • 用足夠多的細節來描述問題發生的場景,你想得到什麼樣的答案?
  • 在求助之前,你做了哪些努力?研究過了嗎?得到了一些線索嗎?

那可能有些人會不服氣,拋下一句狠話:“你這大佬也太不負責任了吧?我就是沒有找到答案才過來找你的啊?我努力了呀?”

冷靜一下哈,提個問題你脾氣這麼大,這麼焦躁,怎麼可能得到答案,對不對?

讓你做準備不是我在逃避責任,而是在教你,教會你自己怎麼解決問題。就拿我來說吧,我已經很少向別人提問題了,除了那隻橡皮鴨。

有生以來,我遇到最痛苦的一個問題就是“可學上往”(寫錯別字,我是認真的),真的,當時我問遍了所有我能問的群,我能問的人,因為這個問題很無解,你了解的。

在向別人求助之前,可行的解決方案就是去問度娘,對吧,但度娘又怎麼會告訴答案呢。有些好心的同行會扔一句“VVPPNN”,然後我就搜啊搜——搜不到答案。

大概折騰了兩周的時間,還是青銅時代群里的一位小夥伴告訴了我答案。由於最近風聲緊,我就不提了。不過,我需要坦誠一句,我“可學上往”純粹是為了寫技術文章用(偶爾 1024 下,不騙你),因為有時候,一些知識點,我自己還沒有掌握,必須得先學習一下,然後才能輸出給讀者。

但度娘有時候給的答案,真的是讓你懷疑人生,那些狗屁不是的帖子它的搜索結果里全都有。但骨骼這方面做得真的是不錯,有一說一。

(這篇文章寫了不少錯別字,不要怪我,我也是被逼的,忍耐一下,看不懂的地方就 YY 一下)

為什麼我很少提問題了呢?

  • 我碰到了一個問題;
  • 我自己研究了一會,沒找到答案;
  • 我決定還是骨骼吧;
  • 我把關鍵詞扔在搜索框里,答案好像還沒找到;
  • 我看了很多帖子,好像答案完全不着邊;
  • 我把問題重新梳理了一遍,準備找技術比我還好的朋友提問;
  • 10 分鐘過去后,我寫下了一百個字,感覺問題已經描述得很清楚了,在好友列表裡準備找朋友了;
  • 突然,我發現好像我搜索的關鍵詞不太對,於是我就換了一個,又換了一個,抱着試一試的心態,結果真的找到了想要的答案。

不知道你有沒有遇到這樣的情況?反正我真的是經歷了無數次。有時候,答案找不到,我都着急得想捶爆鍵盤了,甚至狠狠地在桌子上捶了一拳,疼痛的感覺讓我冷靜下來。

於是我想到了那隻橡皮鴨,我在心裏對它說:“為什麼這台服務器上的首頁打開時間需要一分多鍾,而另外一台服務器上只需要不到三秒鐘?”

“那你有沒有對比兩台服務器有什麼不同嗎?”橡皮鴨開口回答道。

“比對了呀,完全一樣啊,代碼一樣,只是說參數不一樣,war 包也一樣,都用的 Tomcat 啊。”我憤憤不平地說。

“操作系統一樣嗎?”橡皮鴨耐心地開導着我。

“不太一樣,一台是 Windows Server,一台是 CentOS。”我回答道。

“那你有沒有想過把 Windows Server 那台也換成是 CentOS?”橡皮鴨依然很冷靜。

“不會吧,就因為操作系統不同,首頁打開速度差別就會這麼大?”

“你試試唄,把環境備份下,反正現在切換一下操作系統又不麻煩。”

“好的,聽你的,橡皮鴨。”

一個小時后,神奇的事情發生了,原來問題真的是因為 Windows Server 啊!果然不如 Linux 靠譜啊!

以上就是三年前我真實經歷過的,當時有一台遺留的 Windows Server,我就沒想着把操作系統換成是 Linux 的,然後同樣的 war 包放上去后,首頁打開速度超慢,我嘗試過對首頁加上緩存,減少 JavaScript、CSS 文件的大小,對它們進行壓縮,甚至減少了從後台獲取數據的量,但所有的嘗試都於事無補。

最後,真的是橡皮鴨幫助到了我。當你把自己完全投入到一種假想當中,去問一個透徹而詳盡的問題時,答案真的會悄無聲息地找上門來。

大多數情況下,並不是因為我們的知識庫儲備不足,而是我們尋找問題的方向發生了偏離,一旦我們意識到了這種錯誤,問題也就不再是問題。

當然了,當你嘗盡一切辦法,仍然找不到答案的話,找大牛、找朋友、找同事、找社群,不要臉地提問吧,別怕自己受到打擊,別怕問題無人解答,你要做的是,把問題梳理得越來越清晰,也許答案就在你那裡。

如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀。回復關鍵字「簡歷」更有一份技術大佬整理的優質簡歷模板,助你一臂之力。

本文已收錄 GitHub,傳送門~ ,裏面更有大廠面試完整考點,歡迎 Star。

我是沉默王二,一枚有顏值卻靠才華苟且的程序員。關注即可提升學習效率,別忘了三連啊,點贊、收藏、留言,我不挑,嘻嘻

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

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

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

一篇文章快速搞懂 Atomic(原子整數/CAS/ABA/原子引用/原子數組/LongAdder)

前言

相信大部分開發人員,或多或少都看過或寫過併發編程的代碼。併發關鍵字除了Synchronized,還有另一大分支Atomic。如果大家沒聽過沒用過先看基礎篇,如果聽過用過,請滑至底部看進階篇,深入源碼分析。

提出問題:int線程安全嗎?

看過Synchronized相關文章的小夥伴應該知道其是不安全的,再次用代碼應驗下其不安全性:

public class testInt {
    static int number = 0;

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    number = number+1;
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();
        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();
        System.out.println("number:" + number);
    }
}

 

 

運行結果:

在上面的例子中,我們定義一個初始值為0的靜態變量number,再新建並運行兩個線程讓其各執行10萬次的自增操作,如果他是線程安全的,應該兩個線程執行后結果為20萬,但是我們發現最終的結果是小於20萬的,即說明他是不安全的。

在之前Synchronized那篇文章中說過,可以在number=number+1這句代碼上下加Synchronized關鍵字實現線程安全。但是其對資源的開銷較大,所以我們今天再看下另外一種實現線程安全的方法Atomic。

Atomic基礎篇分界線

原子整數(基礎類型)

整體介紹

Atomic是jdk提供的一系列包的總稱,這個大家族包括原子整數(AtomicInteger,AtomicLong,AtomicBoolean),原子引用(AtomicReference,AtomicStampedReference,AtomicMarkableReference),原子數組(AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray),更新器(AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUpdater)。

AtomicInteger

AtomicInteger,AtomicBoolean,AtomicLong三者功能類似,咱就以AtomicInteger為主分析原子類。

先看下有哪些API,及其他們具體啥功能:

public class testInt {

    public static void main(String[] args) {
        //定義AtomicInteger類型的變量,值為1
        AtomicInteger i = new AtomicInteger(1);
        //incrementAndGet方法先新增1再返回,所以打印2,此時i為2
        System.out.println(i.incrementAndGet());
        //getAndIncrement方法先返回值再新增1,所以打印2,此時i為3
        System.out.println(i.getAndIncrement());
        //get方法返回當前i值,所以打印3,此時i為3
        System.out.println(i.get());
        //參數為正數即新增,getAndAdd方法先返回值再新增666,所以打印3,此時i為669
        System.out.println(i.getAndAdd(666));
        //參數為負數即減去,getAndAdd方法先返回值再減去1,所以打印669,此時i為668
        System.out.println(i.getAndAdd(-1));
        //參數為正數即新增,addAndGet方法先新增666再返回值,所以打印1334,此時i為1334
        System.out.println(i.addAndGet(666));
        //參數為負數即減去,addAndGet方法先減去-1再返回值,所以打印1333,此時i為1333
        System.out.println(i.addAndGet(-1));
        //getAndUpdate方法IntUnaryOperator參數是一個箭頭函數,後面可以寫任何操作,所以打印1333,此時i為13331
        System.out.println(i.getAndUpdate(x -> (x * 10 + 1)));
        //最終打印i為13331
        System.out.println(i.get());
    }
} 

 

 

執行結果:

對上述int類型的例子改進

public class testInt {
    //1.定義初始值為0的AtomicInteger類型變量number
    static AtomicInteger number = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100000; i++) {
                    //2.調用incrementAndGet方法,實現加1操作
                    number.incrementAndGet();
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();
        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();
        System.out.println("number:" + number.get());
    }
}

 

 

我們可以看到運行結果是正確的20萬,說明AtomicInteger的確保證了線程安全性,即在多線程的過程中,運行結果還是正確的。但是這存在一個ABA問題,下面將原子引用的時候再說,先立個flag。

源碼分析

我們以incrementAndGet方法為例,看下底層是如何實現的,AtomicInteger類中的incrementAndGet方法調用了Unsafe類的getAndAddInt方法。

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

 

我們看下getAndAddInt方法,裏面有個循環,直接值為compareAndSwapInt返回值為true,才結束循環。這裏就不得不提CAS,這就是多線程安全性問題的解決方法。

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

        return var5;
}

 

CAS

線程1和線程2同事獲取了主內存變量值0,線程1加1並寫入主內存,現在主內存變量值1,線程2也加2並嘗試寫入主內存,這個時候是不能寫入主內存的,因為會覆蓋掉線程1的操作,具體過程如下圖。

CAS是在線程2嘗試寫入內存的時候,通過比較並設置(CompareAndSet)發現現在主內存當前值為1,和他剛開始讀取的值0不一樣,所以他會放棄本次修改,重新讀取主內存的最新值,然後再重試下線程2的具體邏輯操作,再次嘗試寫入主內存。如果這時候線程1,再次對主內存進行了修改,線程2發現現在主內存的值又和預期不一樣,所以將放棄本次修改,再次讀取主內存最新值,再次重試並嘗試寫入主內存。我們可以發現這是一個重複比較的過程,即直到和預期初始值一樣,才會寫入主內存,否則將一直讀取重試的循環。這就是上面for循環的意義。

CAS的實現實際上利用了CPU指令來實現的,如果操作系統不支持CAS,還是會加鎖的,如果操作系統支持CAS,則使用原子性的CPU指令。

原子引用

在日常使用中,我們不止對上述基本類型進行原子操作,而是需要對一些複雜類型進行原子操作,所以需要AtomicReference。

不安全實現

先看不安全的BigDecimal類型:

public class testReference {
    static BigDecimal number = BigDecimal.ZERO;

    public static void main(String[] args) throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                   number=number.add(BigDecimal.ONE);
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();

        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();

        System.out.println(number);
    }
} 

 

 

運行結果如下圖,我們可以看到兩個線程,自循環1000次加1操作,最終結果應該是2000,可是結果小於2000。

安全實現-使用CAS

public class testReference {
    //定義AtomicReference類型BigDecimal變量
    static AtomicReference<BigDecimal> number = new AtomicReference<BigDecimal>(BigDecimal.ZERO);

    public static void main(String[] args) throws Exception {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    //手動寫循環+CAS判斷
                    while(true){
                        BigDecimal pre=number.get();
                        BigDecimal next=number.get().add(BigDecimal.ONE);
                      if(number.compareAndSet(pre,next))  {
                          break;
                      }
                    }
                }
            }
        };

        Thread t1 = new Thread(runnable);
        t1.start();

        Thread t2 = new Thread(runnable);
        t2.start();

        t1.join();
        t2.join();

        System.out.println(number.get());

    }
}

 

 

運行結果如下:

ABA問題及解決

在上面CAS過程中,是通過值比較來知曉是不是能夠更新成功,那如果線程1先加1再減1,這樣主內存還是原來的值,即線程2還是可以更新成功的。但是這樣邏輯錯了,線程1已經發生了修改,線程2不能直接更新成功。

代碼:

public class testInt {

    static AtomicInteger number = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {


        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int a = number.get();
                System.out.println("開始number:" + a);
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(number.compareAndSet(a, a++));


            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("開始增加操作");
                int a = number.incrementAndGet();
                System.out.println("當前number:" + a);
                int b = number.decrementAndGet();
                System.out.println("當前number:" + b);
            }
        });
        t2.start();

        t1.join();
        t2.join();
    }
} 

 

 

我們看線程2對其進行了一系列操作,但是最後打印了還是true,表示可以更新成功的。這顯然不對。

那我們可以使用AtomicStampedReference,為其添加一個版本號。線程1在剛開始讀取主內存的時候,獲取到值為0,版本為1,線程2也獲取到這兩個值,線程1進行加1,減1的操作的時候,版本各加1,現在主內存的值為0,版本為2,而線程2還拿着預計值為0,版本為1的數據嘗試寫入主內存,這個時候因版本不同而更新失敗。具體我們用代碼試下:

public class testInt {

    static AtomicStampedReference<Integer> number = new AtomicStampedReference<Integer>(0, 0);

    public static void main(String[] args) throws Exception {


        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int a = number.getReference();
                int s = number.getStamp();
                System.out.println("開始number:" + a + ",stamp:" + s);
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(number.compareAndSet(a, a + 1, s, s + 1));


            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("開始增加操作");
                int a = number.getReference();
                int s = number.getStamp();
                number.compareAndSet(a, a + 1, s, s + 1);
                System.out.println("當前number:" + a + ",stamp:" + (s + 1));
                a = number.getReference();
                s = number.getStamp();
                number.compareAndSet(a, a - 1, s, s + 1);
                System.out.println("當前number:" + a + ",stamp:" + (s+1));
            }
        });
        t2.start();

        t1.join();
        t2.join();
    }
} 

 

我們可以看到每次操作都會更新stamp(版本號),在最後對比的時候不僅比較值,還比較版本號,所以是不能更新成功的,false.

原子數組

AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray三者類似,所以以AtomicIntegerArray為例,我們可以將下面AtomicIntegerArray看做是AtomicInteger類型的數組,其底層很類似,就不詳細寫了。

AtomicIntegerArray  array = new AtomicIntegerArray(10);
array.getAndIncrement(0);   // 將第0個元素原子地增加1

 

AtomicInteger[]  array = new AtomicInteger[10];
array[0].getAndIncrement();  // 將第0個元素原子地增加1

 

字段更新器和原子累加器比較簡單,這裏就不說了。 

Atomic進階篇分界線

LongAdder源碼分析

LongAdder使用

LongAdder是jdk1.8之後新加的,那為什麼要加他?這個問題,下面將回答,我們先看下如何使用。

public class testLongAdder {
    public static void main(String[] args) throws Exception {
        LongAdder number = new LongAdder();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int j = 0; j < 10000; j++) {
                    number.add(1L);
                }
            }
        };
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("number:" + number);
    }
}

 

我們可以看到LongAdder的使用和AtomicLong大致相同,使用兩個線程Thread1,Thread2對number值各進行一萬次的自增操作,最後的number是正確的兩萬。

與Atomic的對比優勢

那問題來了,既然AtomicLong能夠完成對多線程下的number進行線程安全的操作,那為什麼還要LongAdder?我們先來段代碼比較下,兩個在結果都是正確的前提下,性能方面的差距。

public class testLongAdder {
    public static void main(String[] args) {
       //1個線程,進行100萬次自增操作
        test1(1,1000000);
      //10個線程,進行100萬次自增操作
        test1(10,1000000);
     //100個線程,進行100萬次自增操作
        test1(100,1000000);
    }

    static void test1(int threadCount,int times){
        long startTime=System.currentTimeMillis();
        AtomicLong number1=new AtomicLong();
        List<Thread> threads1=new ArrayList<>();
        for(int i=0;i<threadCount;i++) {
            threads1.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < times; j++) {
                        number1.incrementAndGet();
                    }
                }
            }));
        }
        threads1.forEach(thread -> thread.start());
        threads1.forEach(thread ->{
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } );

        long endTime=System.currentTimeMillis();
        System.out.println("AtomicLong:"+number1+",time:"+(endTime-startTime));

        LongAdder number2=new LongAdder();
        List<Thread> threads2=new ArrayList<>();
        for(int i=0;i<threadCount;i++) {
            threads2.add(new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < times; j++) {
                        number2.add(1);
                    }
                }
            }));
        }
        threads2.forEach(thread -> thread.start());
        threads2.forEach(thread ->{
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } );

        System.out.println("LongAdder:"+number2+",time:"+(System.currentTimeMillis()-endTime));

    }
} 

 

上述代碼對比了1個線程,10個線程,100個線程在進行100百次自增操作后,AtomicLong和LongAdder所花費的時間。通過打印語句,我們發現在最終number1和number2都正確的基礎上,LongAdder花費的時間比AtomicLong少了一個量級。

源碼分析

那為什麼會導致這種情況,我們就要從源碼層面分析。AtomicLong為什麼效率低?因為如果線程數量一多,尤其在高併發的情況下,比如有100個線程同時想要對對象進行操作,肯定只有一個線程會獲取到鎖,其他99個線程可能空轉,一直循環知道線程釋放鎖。如果該線程操作完畢釋放了鎖,其他99個線程再次競爭,也只有一個線程獲取鎖,另外98個線程還是空轉,直到鎖被釋放。這樣CAS操作會浪費大量資源在空轉上,從而使得AtomicLong在線程數越來越多的情況下越來越慢。

AtomicLong是多個線程對同一個value值進行操作,導致多個線程自旋次數太多,性能降低。而LongAdder在無競爭的情況,跟AtomicLong一樣,對同一個base進行操作,當出現競爭關係時則是採用化整為零的做法,從空間換時間,用一個數組cells,將一個value拆分進這個數組cells。多個線程需要同時對value進行操作時候,可以對線程id進行hash得到hash值,再根據hash值映射到這個數組cells的某個下標,再對該下標所對應的值進行自增操作。當所有線程操作完畢,將數組cells的所有值和無競爭值base都加起來作為最終結果。

我們先看下LongAdder裏面的字段,發現其裏面沒有,主要是在其繼承的Stripped64類中,有下面四個主要變量。

 /** CPU數量,即cells數組的最大長度*/
    static final int NCPU = Runtime.getRuntime().availableProcessors();

    /**
     *cells數組,為2的冪,2,4,8,16.....,方便以後位運算
     */
    transient volatile Cell[] cells;

    /**
     * 基值,主要用於沒有競爭的情況,通過CAS更新。
     */
    transient volatile long base;

    /**
     * 調整單元格大小(擴容),創建單元格時使用的鎖。
     */
    transient volatile int cellsBusy;

 

 

下面是add方法開始。

 public void add(long x) {
        //as:cells數組的引用
        //b:base的基礎值
        //v:期望值
        //m:cells數組大小
        //a:當前數組命中的單元
        Cell[] as; long b, v; int m; Cell a;
        //as不為空(cells已經初始化過,說明之前有其他線程對初始化)或者CAS操作不成功(線程間出現競爭)
        if ((as = cells) != null || !casBase(b = base, b + x)) {
        //初始化uncontented,true表示未競爭(因為有兩個情況,這裏先初始化,後面對其修改,就能區分這兩種情況)
        boolean uncontended = true;
        //as等於null(cells未初始化)
        //或者線程id哈希出來的下標所對應的值為空(cell等於空),getProbe() & m功能是獲取下標,底層邏輯是位運算
        //或者更新失敗為false,即發生競爭,取非就為ture
        if (as == null || (m = as.length - 1) < 0 ||
                (a = as[getProbe() & m]) == null ||
                !(uncontended = a.cas(v = a.value, v + x)))
        //進入到if裏面,說明更新case失敗,或者更新某個cell也失敗了,或者cell為空,或者cells為空
                longAccumulate(x, null, uncontended);
        }
    }

 

從LongAdder調用Stripped64的longAccumulate方法,主要是初始化cellscells的擴容多個線程同時命中一個cell的競爭操作。

final void longAccumulate(long x, LongBinaryOperator fn,
                              boolean wasUncontended) {
        //x:add的值,fn:為null,wasUncontended:是否發生競爭,true為發生競爭,false為不發生競爭
        int h;//線程的hash值
        //如果該線程為0,即第一次進來,所以ThreadLocalRandom強制初始化線程id,再對其hash
        if ((h = getProbe()) == 0) {
            ThreadLocalRandom.current(); 
            h = getProbe();
            wasUncontended = true;
        }
        //擴容意向,為false肯定不擴容,為true可能擴容
        boolean collide = false; 
        //死循環               
        for (;;) {
            //as:cells數組的引用
            //a:當前線程命中的cell
            //n:cells的長度
            //v:當前線程命中的cell所擁有的value值
            Cell[] as; Cell a; int n; long v;
            //cells不為空
            if ((as = cells) != null && (n = as.length) > 0) {
                //當前線程命中的cell為空,下面邏輯是新增cell
                if ((a = as[(n - 1) & h]) == null) {
                    if (cellsBusy == 0) {       // Try to attach new Cell
                        Cell r = new Cell(x);   // Optimistically create
                        if (cellsBusy == 0 && casCellsBusy()) {
                            boolean created = false;
                            try {               // Recheck under lock
                                Cell[] rs; int m, j;
                                if ((rs = cells) != null &&
                                    (m = rs.length) > 0 &&
                                    rs[j = (m - 1) & h] == null) {
                                    rs[j] = r;
                                    created = true;
                                }
                            } finally {
                                cellsBusy = 0;
                            }
                            if (created)
                                break;
                            continue;           // Slot is now non-empty
                        }
                    }
                    collide = false;
                }
                //發生競爭
                else if (!wasUncontended)       // CAS already known to fail
                    wasUncontended = true;      // Continue after rehash
                //沒有競爭,嘗試修改當前線程對應的cell值,成功跳出循環
                else if (a.cas(v = a.value, ((fn == null) ? v + x :
                                             fn.applyAsLong(v, x))))
                    break;
                //如果n大於CPU最大數量,不可擴容
                else if (n >= NCPU || cells != as)
                    collide = false;            // At max size or stale
                else if (!collide)
                    collide = true;
                //獲取到了鎖,進行擴容,為2的冪,
                else if (cellsBusy == 0 && casCellsBusy()) {
                    try {
                        if (cells == as) {      // Expand table unless stale
                            Cell[] rs = new Cell[n << 1];//左移一位運算符,數量加倍
                            for (int i = 0; i < n; ++i)
                                rs[i] = as[i];
                            cells = rs;
                        }
                    } finally {
                        cellsBusy = 0;
                    }
                    collide = false;
                    continue;                   // Retry with expanded table
                }
                h = advanceProbe(h);
            }
            //cells等於空,並且獲取到鎖,開始初始化工作,創建結束釋放鎖,繼續循環
            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
                boolean init = false;
                try {                           // Initialize table
                    if (cells == as) {
                        Cell[] rs = new Cell[2];
                        rs[h & 1] = new Cell(x);
                        cells = rs;
                        init = true;
                    }
                } finally {
                    cellsBusy = 0;
                }
                if (init)
                    break;
            }
            else if (casBase(v = base, ((fn == null) ? v + x :
                                        fn.applyAsLong(v, x))))
                break;                          // Fall back on using base
        }
    }

 

 

結語

結束了,撒花。這篇主要說了Atomic的一些使用,包括Atomic原子類(AtomicInteger,AtomicLong,AtomicBoolean),Atomic原子引用(AtomicReference,AtomicStampedReference),以及1.8之後LongAdder的優勢,源碼分析。過程還穿插了一些CAS,ABA問題引入和解決方式。

 

參考資料

Java多線程進階(十七)—— J.U.C之atomic框架:LongAdder

CAS原理

Java 8 Performance Improvements: LongAdder vs AtomicLong

AtomicInteger深入理解

原子操作類AtomicInteger詳解

玩轉Java併發工具,精通JUC,成為併發多面手

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

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

台中搬家公司費用怎麼算?

10.99萬起 神車朗逸 軒逸都忌憚的車型哪款車型最值得買?

精英型和豪華型相差10000元了,不多倒是也多出了這麼多的配置,像無鑰匙啟動、真皮坐椅、中控屏幕、氙氣大燈、自動空調等這些配置,就算自己後期去加裝也要花不少錢,況且這些配置最好還是原車帶的比較靠譜,自己加裝的東西出問題又不在質保範圍內。

朗逸的銷量雖好,但是身後也有無數強敵,其中英朗算是一個強有力的競爭對手。英朗在10月份的銷量為34629輛,1-10月份累加銷量為303116輛,這數據真的是亮瞎眼。

英朗的指導價為10.99-15.99萬,車身尺寸為4587*1798*1463mm,軸距為2640mm,英朗的車長沒有達到4600mm以上算是一個遺憾,因為同級別的車子長度都超過了4600mm,不過好在英朗的外觀設計比較大氣,同時軸距不小,所以後排空間還是比較充裕的。

英朗的中控內飾用料以硬塑料為主,這也是這個級別通常的配置,不過英朗的內飾看起來設計感十足,層次感突出,體現出了別克內飾設計的“環繞的感覺”,看起來稍顯高檔。

英朗的動力系統為1.5L 114馬力+5擋手動/6擋手自一體、1.4T 144馬力+7擋雙離合,目前英朗有九款在售車型,消費者面對這麼多的車型,肯定是有點迷茫的,所以今天小編就給大家看一下英朗的哪款車性價比最高,爭取在買車的時候買到最實惠的從車型。

1.5L車型的手動擋和自動的差價在1萬元,也就是1萬元買了一台6AT變速箱。進取型、精英型、豪華型的其它配置是一樣。

低配和次低配差價8000元,主要多了前排側氣囊、天窗、雷達等,對於那些經常吸煙或者買車必須要天窗的消費者來說,精英版還是合適的。但是對於不要求配置的消費者來說,進取型就足夠了。

精英型和豪華型相差10000元了,不多倒是也多出了這麼多的配置,像無鑰匙啟動、真皮坐椅、中控屏幕、氙氣大燈、自動空調等這些配置,就算自己後期去加裝也要花不少錢,況且這些配置最好還是原車帶的比較靠譜,自己加裝的東西出問題又不在質保範圍內。

所以豪華版是為那些比較看重配置消費者準備的。

說完了1.5L車型,接下來該說一說1.4T車型,1.4T車型有三個型號,分別是精英型、豪華型、旗艦型。其中精英型和1.5L的精英型配置相同。

所以頂配車型更多的只是為了提高自身形象,性價比較低。倒是精英和豪華型具有一定的性價比。

總結:其實我們是不怎麼建議消費者選擇雙離合車型,因為變速箱的調教還不是很完美,0-100km/h加速大約為10.2s,成績也不是很理想。所以最好的選擇就是1.5L車型,如果資金不充足進取型就可以,在乎天窗了就精英型,對配置有要求了可以選擇豪華型。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

奇駿 途觀都被逼至絕路!這新款SUV顏值操控同級無敵?

內飾上也是進行了重新設計,用料也更為厚道,相當於原來的中庸內飾設計,現款設計無疑更為時尚。加入懸浮式中控屏幕以及改變了空調出風口的形狀。儀錶盤依然是三錶盤式設計,中規中矩,若是可以能把轉速表放在中央相信能贏得更多馬粉的喜歡。

前言

馬自達的車型對於很多消費者來說就像是夢中情人的存在,非常喜歡但可能因為價格、實用性等問題最後卻是選擇其他的車型。而在今年剛剛開幕的洛杉磯車展上,馬自達給我們帶來了最新的CX-5,那麼它有着什麼樣的改變?是否能讓人突破理性果斷將其開回家?

2017款CX-5使用的依然是馬自達近年來力推的魂動設計,所以它看起來還是給到我們比較熟悉的感覺,但是相對於現款的設計,無疑是更為激進動感,在顏值方面再次領跑整個緊湊型SUV。

大燈方面變得更為凌厲,而且尺寸也相對小了。進氣格柵面積更大,並且從原本有着的鍍鉻裝飾變成了現在的黑色網狀格柵,更像是一輛性能車,一改現款的儒雅氣質,突顯了自己的凌厲氣質。

大燈光源上始終使用的是氙氣大燈,不過LED日間行車燈效果佳,造型漂亮。

得益短后懸的設計,2017款CX-5看起來更為緊湊。除此以外,馬自達還增大了A柱的角度帶來了更佳的視野,降低了重心以及更寬的輪距以求有着更為優秀的操控表現,所以最佳操控緊湊型SUV的地位CX-5是再次坐實了。

大尺寸輪轂配合短前後懸的設計使得新CX-5車身更為緊湊,車頭前吻是整車中最為性感的部分。

家族化設計使得CX-5在尾部沒有太多的新意,但總歸是更為動感,上方的擾流板相當個性。

內飾上也是進行了重新設計,用料也更為厚道,相當於原來的中庸內飾設計,現款設計無疑更為時尚。加入懸浮式中控屏幕以及改變了空調出風口的形狀。

儀錶盤依然是三錶盤式設計,中規中矩,若是可以能把轉速表放在中央相信能贏得更多馬粉的喜歡。

在空間表現上將於現款持平,所以空間和競爭對手相比還是處於劣勢,不過加入了傾角可調節式的後排座椅,後排還是可以坐得比較舒適的。

寬大的座椅是佔據空間的大戶,但是這樣乘坐舒適度,尤其是長途時就有着很大的保證。

動力方面將維持現款的2.0L以及2.5L創馳藍天發動機,配搭的是6AT變速箱,油耗表現優秀。

價格方面相信將維持現款的17-25萬區間,據悉2017款將在下一年引進國產,這款全新的CX-5在外觀內飾上以及操控上有了一定的提升 ,相對於其他車企的改款來說這相當的厚道,不過在國人重視的空間方面馬自達始終沒能交出一份滿意的結果。對此,你願意為這“夢中情人”埋單嗎?還是覺得“可遠觀而不可褻玩焉”?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

這款轎車標配ESP起價只有5萬多 10月份還賣了1.6萬台!

所以小編這次就是要給大家說說艾5哪款車的性價比最高。下面兩個圖表分別是手動擋車型和自動擋車型。其中艾5標配主/副駕駛座安全氣囊、ESp、上坡輔助、后視鏡電動調節。所以如果預算不充足,即使最低配的艾5,也是可以入手的。

自主SUV異常火爆是眾所周知的,但是自主轎車在和合資轎車的對抗中一直出於劣勢,所以不少人都唱衰自主轎車。

但是事情總會有轉機的,只要廠家拿出有誠意的作品,銷量一定不會差的。比如奇瑞艾瑞澤5(本文簡稱艾5),這款起步價只有5.89萬的緊湊型轎車,要保證顏值和空間的情況下,竟然全系標配了ESp,正是因為如此厚道的配置,所以艾5的10月份銷量為16504輛。表現非常好。

艾5在今年3月18日上市,指導價為5.89-9.79萬,上市之後就取得了很大的反響,之所以引起巨大的關注,一是因為艾5的的原創性很高,在細節方面都突出了年輕化的設計理念。車頭造型飽滿,中網樣式類似“滿天星”,這樣的設計也使前格柵的層次感較為豐富。

二是因為艾5的配置確實不低。艾5的車身尺寸為4572*1825*1482mm,軸距為2670mm,標準的緊湊型轎車,不小的軸距極大的保證了車內空間。同時配置很高,即使是最低配,也是標配了ESp,從這一點可以看出這個企業還是挺實在的。

正是因為企業的“實在”,所以才得到了消費者的認可。但是當消費者去選擇艾5的時候,會發現密密麻麻一堆車型看起來就頭疼。所以小編這次就是要給大家說說艾5哪款車的性價比最高。下面兩個圖表分別是手動擋車型和自動擋車型。

其中艾5標配主/副駕駛座安全氣囊、ESp、上坡輔助、后視鏡電動調節。所以如果預算不充足,即使最低配的艾5,也是可以入手的。

通過圖表可以發現,撇開手動擋最低配和自動擋高配,其餘的手動擋和自動擋都是相互對應的,價格差了8000元,但是其它配置一樣的,所以相當於8000買個一台CVT變速箱,所以我們就以手動擋車型為例子進行分析。

通過上圖我們發現,雖然低配的性價比不低,但是和次低配領潮版比起來,性價比還是沒有領潮版高。

領潮版、智效領動版、領銳版相比起來,首先排除智效領動版,性價比最低。雖然領銳版售價已經接近7萬,但是多出的配置還是比較實用的。所以領銳版也有一定的性價比。

對於再高級別的領跑版和領臻版,無非就是多個氣囊、GpS,不過價格已經過高,對於艾5這款主打性價比的車子,顯然是不會受歡迎的。不過如果資金充足的話也可以選擇手動或者自動領臻版,安全配置比較豐富。

對於售價高達9.79萬的頂配車型-自動領尊版,更多的是為了提升品牌形象,幾乎完全沒有性價比。

綜上所述,領潮版的性價比最高了,其次是領銳版,同時最低配的手動領尚版性價比也不錯。其它車型的性價比不是很高。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準

廣州現場精彩不斷 奧德賽主場熱力開局

“全能MpV”奧德賽具備了魔方式的空間變換組合,可以根據不同場合的需求自由切換:除了可以乘坐7人的正常模式以外,還可以放倒部分第三排座椅,變為“休閑模式”或“超長模式”,更能將後排完全收起放平,變為“超大模式”。

在個人色彩越來越濃的今天

我們在職場上八面玲瓏,進退自如

但一轉身,面對與最親近的家人溝通

卻往往不知該如何應對……

11月的廣州依舊“熱情”高漲,而這份熱情也同樣延續到了11月12日在廣州舉辦的奧德賽非凡品鑒會活動現場。作為繼上海、北京之後又一場有別傳統的非凡品鑒會,坐鎮主場的奧德賽此番同樣延續了熱播綜藝《飯局的誘惑》節目熱潮,誠邀兩位金牌辯手現場與大家分享傳授說話之道,在欣賞奧德賽非凡魅力的同時,現場觀眾更是得到了智、情、局三商的全方位提升。

事實上,《飯局的誘惑》作為奧德賽與綜藝大咖馬東聯手打造的一檔綜藝節目,節目中高智商高情商的語言對壘令觀眾朋友大呼過癮。同樣的,以雙商詮釋自我產品特點的奧德賽在節目中頻繁亮相,更是成為嘉賓主持話梗里的經典“橋段”。也正因此,在非凡品鑒會上,奧德賽同樣將“說話的藝術”搬到了現場,在全方位展示自身產品實力的同時,更是將智、情、局三商的精髓應用到了日常生活之中。

延續高雙商開局 ,奧德賽掌控生活格局

Talk show環節,一如在前兩站中,“金牌辯手”們教會了大家如何應付生活中的各種尷尬,廣州站品鑒會上,馬薇薇與黃執中同樣為大家準備了新鮮的生活話題。

現場,金句女王馬薇薇首先與大家分享了如何在家庭生活中以“分”為貴,即在家庭關係中分清是“男權”還是“平權”為主;分清楚想要從原生家庭得到什麼就必須失去什麼;分清楚在自己組建的新家庭里是願意當主人還是當“孩子”。把握家庭話語權,例如馬薇薇提及在平權家庭中,面對出行問題時則必須共同承擔,在帶上自己父母的同時更要照顧到對方的父母。也正因此,像奧德賽這樣至少能夠容下6個人的車才是出行的必需品。

而事實上,作為一款7座MpV車型,奧德賽擁有2+2+3的座椅布局,在日常出行中,與一家三口的需求完美匹配,可以盡享第二排航空座椅的舒適體驗。即便是再帶上雙方父母,奧德賽的座位和空間也是綽綽有餘。這便是奧德賽對於家庭出行更為全面的考慮,也足以凸顯出其高情商的一面。

對於家庭生活的妥善處理,在網絡上一向以“情感專家”著稱的黃執中更是以男性視角深入剖析,教會大家如何利用情商照顧到身邊的每一個人。在談話中,黃執中提出:在遇到問題時不應關注事件本身,而是當事人雙方感覺的問題;在討論問題時不應站在對立面,而是轉換方式,一同面對問題;最終即便問題解決,也應該從對方得失心出發給予一定的安慰,讓對方知道她的委屈你能懂。簡而言之,黃執中用超高的情商詮釋了面對尷尬處境時如何照顧全局,細緻巧妙的處理也贏得了在場觀眾的掌聲。

正如黃執中說的那樣,奧德賽對於“掌控全局”也同樣非常在行。“全能MpV”奧德賽具備了魔方式的空間變換組合,可以根據不同場合的需求自由切換:除了可以乘坐7人的正常模式以外,還可以放倒部分第三排座椅,變為“休閑模式”或“超長模式”,更能將後排完全收起放平,變為“超大模式”。無論是全家外出的座位需要,亦或是商務接待需要的車內空間,奧德賽都能輕鬆掌控。

情景演繹扣人心弦,奧德賽解碼非凡亮點

與傳統品鑒會相比,非凡品鑒會的現場可謂處處不同。除了引人入勝的talk show環節,現場講師對產品的解讀也是別具一格。通過場景的植入與話題的點撥,講師從“撥、移、躺、藏、開”多角度深入,為現場觀眾生動解碼了奧德賽的非凡體驗點。

以“移”為例,在講解過程中,講師通過實際的例子為大家詮釋了奧德賽超低車門踏板設計的用意。原來,在設計之初,考慮到一些身着裙裝的女性能夠方便上下車,同時也照顧到老人小孩的乘坐便利,奧德賽在保證通過性的同時,將油箱做的更扁平,合理化配置的前提下,為乘客提供了最佳的上下車高度。奧德賽用高智商和高情商的雙商完美解決了問題。

亦動亦靜,全方位感受奧德賽非凡一面

靜態展示體驗部分,現場的一輛“特殊”展車令不少人眼前一亮。作為企業社會化責任的一部分,同時也作為車系派生車型的進一步完善,奧德賽福祉車的亮相無疑是場上的另一大看點。通過遙控二排可升降旋轉座椅,短短十幾秒內,行動不便的乘客無需自己挪動便可輕鬆實現上下車動作,方便之餘也再次體現出奧德賽全方位人性化的設計理念。

當然,除了靜態展示部分,品鑒會又怎少的了試駕環節。不同與上海站與北京站的路況,廣州站的試駕路線採用了“直線”加“調頭”的模式。試駕時,體驗者不僅能夠感受到“黃金動力組合”下奧德賽CVT無級變速箱的平順加速動力,同時,在調頭部分中更可感受奧德賽同級最小轉彎半徑的優勢。這樣的專項試駕也令不少體驗者印象深刻。

除了靜態展示和試乘試駕部分外,主辦方還為親臨現場體驗的來賓準備了奧德賽全能生活非凡禮遇。豐盛的現金禮遇和置換福利表現也令不少來賓現場簽訂購車意向。奧德賽的高局商則恰恰體現在此。

從職場到生活,從同事相處到家庭關係,奧德賽攜多位名嘴辯手與大家分享了職場人生中的說話之道,用一個個生動有趣的例子完美詮釋了高智商高情商的人生格局。創新、趣味、智慧、尊享,這就是奧德賽非凡品鑒會留給在場所有人的印象。而下一站深圳,活動即將迎來收官站,屆時,名嘴嘉賓又將有哪些辛辣犀利的話題與大家分享,奧德賽與你一同見證非凡本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

※回頭車貨運收費標準

城市SUV就不能越野?這些20萬級的SUV不僅能家用還能出去野!

98-22。98萬元水平對置發動機、左右對稱四驅系統,這都是斯巴魯強有力的武器,一直以來只能通過進口途徑購買的斯巴魯汽車給人感覺都是售價不便宜。而事實上斯巴魯有一款最低售價低於二十萬的SUV,那就是斯巴魯XV。對了,斯巴魯車配件都是進口的,所以維修保養的成本會相對高一點。

叫獸之前發過一篇文章說硬派SUV在操控、舒適性、動力調校等方面的表現導致其不適合城市的駕駛。然而事實上像叫獸這種從山裡走出來的孩子,雖然平時在城市裡混,但過年過節還是必須開車回家才夠意思的,不然買車有什麼意義?對吧。所以一輛既能在城市輕鬆駕駛,跑爛路的時候又有較好通過性的SUV,就最適合叫獸了。眼看着要年底了,叫獸跟你們分享一下這樣的車有哪些吧。

東風日產-奇駿

指導價:18.18-26.78萬元

硬朗平直的車身,優秀的四驅系統,同級別幾乎最好的通過性,這是上一代奇駿給叫獸留下的印象。而在售的這一代奇駿,雖然外觀進行了脫胎換骨的變化,變得更加接近時尚的城市SUV了,但其優秀的越野性能還是得以保留。

外觀方面,奇駿對比同級別的對手在尺寸方面有一定的優勢,所以觀感上奇駿會顯得高大,配合上稍帶有肌肉感的線條,奇駿的外觀還是頗具霸氣的,實際上奇駿的定位只是緊湊型SUV。

奇駿的內飾採用懷抱式的設計,線條流暢柔和,十分有親和力。日產車的內飾做工在日系車裡面算是做得優秀的一個了,尤其是奇駿這種有輕度越野需求的車,做工差的話異響就會特別明顯。還有一個就是奇駿的中控屏比較小,沒有導航,但有全景影像,比較實用。

奇駿最便宜的四驅車型為2.0L的智享版,算上優惠的話,落地價估計也就二十萬出頭,性價比還是蠻突出的。最大馬力為150ps,搭載CVT變速箱,動力輸出線性,低扭有力,該發動機的日常行駛很輕快。

奇駿的前後橋有開放式差速器,能夠鎖止打滑的車輪,所以該車是有能力通過交叉軸的,同時奇駿的車身剛度不錯,最小離地間隙為210mm,接近角為17°,底盤質感沉穩,濾震效果好。綜合這些數據和表現,奇駿應對輕度的越野還是綽綽有餘的。

廣汽三菱-歐藍德

指導價:15.98-22.38萬元

三菱歐藍德之前都是以進口車的身份活躍在國內市場,二十來萬的價格,三菱的血統,進口的品質,進口版歐藍德的口碑一直不錯。而直到今年,姍姍來遲的合資歐藍德終於和我們見面,合資的歐藍德原汁原味的保留了進口歐藍德的設計,不同的是價格更加優惠了

廣汽三菱歐藍德的造型和進口版車型是高度一致的,車頭造型比進口版的舊款要開揚和順眼不少,寬大的格柵十分霸氣,只是鍍鉻的裝飾稍微偏多了。側面的造型十分修長,因為歐藍德有着4695mm的車身長度,至於車尾則比車頭要低調很多,圓潤的造型有點像旅行車的車尾。

內飾造型的變化也不大,還是熟悉的日系居家風格,最明顯的變化是中控大屏從7英寸換成了8英寸,但這個大屏比新勁炫上面那一塊真的要和諧很多,不會太突兀。配置方面有防碰撞預警和ACC,還是挺實用的。

動力方面,只有最低配採用2.0L的發動機,其餘三個配置均為2.4L+CVT的四驅車型,最大馬力192ps,認為如果買歐藍德不買四驅版本,那還不如買一台XRV了。2.4L版本的歐藍德低扭表現出色,起步有力,動力輸出平順,但畢竟車重擺在那,歐藍德不能給你很強烈的加速快感。

歐藍德採用一套適時四驅系統,有三種驅動模式供駕駛者選擇,實際測試中,交叉軸、單前輪着地的三開放式滑輪組都可以通過,只是电子系統的反應還是有點慢。歐藍德的整體越野能力值得肯定,畢竟他主要還是一輛城市SUV啊。

斯巴魯-斯巴魯XV

指導價:18.98-22.98萬元

水平對置發動機、左右對稱四驅系統,這都是斯巴魯強有力的武器,一直以來只能通過進口途徑購買的斯巴魯汽車給人感覺都是售價不便宜。而事實上斯巴魯有一款最低售價低於二十萬的SUV,那就是斯巴魯XV。對了,斯巴魯車配件都是進口的,所以維修保養的成本會相對高一點。

叫獸覺得斯巴魯XV的外觀對比常見的SUV來說稍顯另類,車身造型扁平,長度比同級對手要短,車身重心也比較低,整體的造型更加接近於跨界車。

內飾方面,斯巴魯XV的採用對稱式的布局,內飾材料主要為塑料,做工很好,接縫緊密而均勻,但新款在內飾上的變化依然不大。讓叫獸欣慰的是在配置方面,斯巴魯XV有不少的提升,如胎壓監測、發動機啟停、空調溫度分區控制等等。不過話又說回來,這些配置,自主品牌十來萬的車早就有配備了。

動力方面,斯巴魯XV搭載了2.0L的水平對置4缸發動機,最大馬力150ps,變速箱則為CVT。和大部分的日系車一樣,斯巴魯XV的動力表現並不算积極,雖然起步輕快,但後段的動力儲備明顯不足,而且CVT變速箱又不適合急加速,所以斯巴魯XV只適合安安分分的駕駛。

斯巴魯XV搭載全時四驅系統,由於水平對置發動機重心低,所以XV的行駛穩定性很好。但重心低不代表通過性差,220mm的最低離地間隙讓XV能夠輕鬆應對爛路。左右對稱四驅系統能根據行駛狀況調整前後軸的扭力分配,這就讓斯巴魯XV比普通的城市SUV擁有有更強的脫困能力了。

廣汽菲克Jeep-自由光

指導價:20.98-31.58萬元

在Jeep還是只能進口的時代,想要二十來萬買一台軸距2705mm的Jeep中型SUV那幾乎就是天方夜譚。但現在不同了,合資國產後的自由光定價親民了不少,想體驗一下Jeep的中型SUV,自由光是最佳選擇了。

國產自由光的外觀和進口自由光的外觀差別不大,第一眼看的時候甚至會覺得有點怪,但時間長了之後就會發現其實自由光的外觀設計還是挺有意思的。七孔造型的中網辨識度好高,細條狀造型的頭燈也很有時尚感,自由光的外觀設計很大膽,越看越有味道。

內飾方面,對稱式的布局,維持了進口版上的設計,實質上自由光的內飾帶有一點歐洲車的風格,簡單而有檔次感。至於用料方面又體現了美系車的大方,不會吝嗇皮質材料的使用。座椅也和美系大沙發一樣,填充厚實,舒適性出色。

自由光有2.0L和2.4L兩種排量,變速箱均為ZF的9AT,最大馬力分別是155ps和175ps,叫獸認為想體驗更加接近Jeep的駕駛感受,2.4L專業版以上帶有適時四驅系統的車型會更加合適。可惜由於車重較大,175ps的馬力也僅能夠用,市區的行駛十分溫和舒適,沒什麼爆發力可言。

廣汽菲克Jeep-自由光搭載的是入門的Active Drive I四驅系統,有不錯的燃油經濟性,四驅西東也能適當的根據路況來分配各車輪的動力。所以整體來說自由光還是有能力應對一些泥濘道路或者打滑不是十分嚴重的脫困。

總結:雖說現在國家的經濟發展相當繁榮,但路況不好的小縣城或者農村還是不在小數。購買SUV除了是因為其相對霸氣的外形以外,更好的通過性和越野性能才是最能體現它實用的地方。又是年近歲晚的時候,相信不少人都盤算着怎樣回家過年,不知道今年你們有沒有考慮開上一輛四驅SUV回去?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

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

憋大招 陸風將推出全新概念車

此概念車採用了跨界車的設計風格,前臉的設計感較強,中網採用了較為規整的網格格柵,並且進氣格柵與兩側的大燈相連融會貫通,整體很有科技感。下方的霧燈區域,摒棄了傳統的矩形或圓形燈組造型,轉而採用誇張的C型設計,辨識度很強,同時周邊的線條設計也增強了運動感。

隨着國內汽車市場的發展,自主品牌近年在設計上的提升是我們有目共睹的。在本次廣州車展上,不少企業將推出“高顏值”的車型,而在眾多高顏值的車型中最為吸引眼球的是我們自主品牌陸風旗下的一款定位時尚跨界緊湊型SUV概念車。

眾多的“高顏”車型中為什麼只看上了陸風這款車?難不成這款車擁有傲視群雄的品質?先別急聽給你好好扒一扒,拋開品質的變化之大暫且不論,單就外觀的設計以及家族式風格的蛻變,就能很明顯得看出如今陸風品牌的設計能力和品牌變化的巨大。

外觀設計的成功意味着什麼?難道只是換一個設計師設計造型那麼簡單?其實不然,通過對外觀設計風格的變化,我們能看出一款車型品牌的壯大、車企對市場方向的把控能力、對潮流市場引領的方向,這絕對是值得我們關注和探究的。

說了“辣么多”我們還是聊回陸風這款顏值擔當吧。

這款定位為時尚跨界緊湊型SUV概念車,就是陸風將於廣州車展亮相的一款重磅車型,並計劃於明年正式投入生產。講真,在第一眼看見陸風的這一款概念車的時候,完全就是被它的車身側面造型所吸引過去的,全然不知這竟然是一款自主品牌的SUV。

此概念車採用了跨界車的設計風格,前臉的設計感較強,中網採用了較為規整的網格格柵,並且進氣格柵與兩側的大燈相連融會貫通,整體很有科技感。下方的霧燈區域,摒棄了傳統的矩形或圓形燈組造型,轉而採用誇張的C型設計,辨識度很強,同時周邊的線條設計也增強了運動感。配合時尚的保險杠設計,提升了整車的運動及越野氣質,讓人感覺“野性”十足。

如果車頭造型還沒能打動你,那車身側面一定能讓你心花怒放。側面大角度傾斜的後窗玻璃與發動機蓋隆起的線條,使得這款車頗具美系車的肌肉感,搭配上巨大的輪圈和貫穿全車的側面雙腰線的設計,為車身帶來了修長的視覺效果,真是非常符合像這樣的年輕人口味。

動力方面據本次車展工作人員透露,未來量產車型動力方面,其匹配的1.5T缸內直噴汽油引擎及最新一代CVT變速器,將帶來絕佳的駕駛體驗,將在明年下半年正式上市。

【點評】:在2016年各大自品牌都發力SUV市場的激烈競爭下,陸風X7能在眾多競品中突圍而出尤為難得。從陸風汽車的產品布局來看,現階段將全部精力都投放到SUV產品中來,從這款定位時尚跨界緊湊型SUV概念車的亮相足矣看出,這是陸風集團聚萬千心血於一身的產品。

同時也能從產品看出,陸風汽車是具有極強自主設計能力的車企,在這個“顏”字當先的時代,高顏值勢必會成為本次車展各類新車的大趨勢,而這款概念車無疑是此次車展的高顏者,有興趣的朋友可以到廣州車展現場,陸風展台(1.2號館 2A01展位),一睹這款概念車的靚相。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

※回頭車貨運收費標準

台中搬家公司費用怎麼算?