120行代碼打造.netcore生產力工具-小而美的後台異步組件

相信絕大部分開發者都接觸過用戶註冊的流程,通常情況下大概的流程如下所示:

  1. 接收用戶提交註冊信息
  2. 持久化註冊信息(數據庫+redis)
  3. 發送註冊成功短信(郵件)
  4. 寫操作日誌(可選)

偽代碼如下:

public async Task<IActionResult> Reg([FromBody] User user)
{
    _logger.LogInformation("持久化數據開始");
    await Task.Delay(50);
    _logger.LogInformation("持久化結束");
    _logger.LogInformation("發送短信開始");
    await Task.Delay(100);
    _logger.LogInformation("發送短信結束");
    _logger.LogInformation("操作日誌開始");
    await _logRepository.Insert(new Log { Txt = "註冊日誌" });
    _logger.LogInformation("操作日誌結束");
    return Ok("註冊成功");
}

在以上的代碼中,我使用Task.Delay方法阻塞主線程,用以模擬實際場景中的執行耗時。以上流程應該是包含了絕大部分註冊流程所需要的操作。對於任何開發者來講,以上業務流程沒任何難度,無非是順序的執行各個流程的代碼即可。

稍微有點開發經驗的應該會將以上的流程進行拆分,但有些人可能就要問了,為什麼要拆分呢?拆分之後的代碼應該怎麼寫呢?下面我們就來簡單聊下如此場景的正確打開方式。

首先,註冊成功的依據應該是是否成功的將用戶信息持久化(至於是先持久化到數據庫,異或是先寫到redis不在本篇文章討論的範疇),至於發送註冊短信(郵件)以及寫日誌的操作應該不能成為影響註冊是否成功的因素,而發送短信/郵件等相關操作通常情況下也是比較耗時的,所以在對此接口做性能優化時,可優先考慮將短信/郵件以及寫日誌等相關操作與主流程(持久化數據)拆分,使其不阻塞主流程的執行,從而達到提高響應速度的目的。

知道了為什麼要拆,但具體如何拆分呢?怎樣才能用最少的改動,達到所需的目的呢?

條條大路通羅馬,所以要達成我們的目的也是有很多方案的,具體選擇哪種方案需要根據具體的業務場景,業務體量等多種因素綜合考慮,下面我將一一介紹分析相關方案。

在正式介紹可用方案前,筆者想先介紹一種很多新手容易錯誤使用的一種方案(因為筆者就曾經天真的使用過這種錯誤的方案)。

提到異步,絕大部分.net開發者應該第一想到的就是Task,async,await等,的確,async,await的語法糖簡化了.net開發者異步編程的門檻,減少了很多代碼量。通常一個返回Task類型的方法,在被調用時,會在方法的前面加上await,表示需要等待此方法的執行結果,再繼續執行後面的代碼。但如果不加await時,則不會等待方法的執行結果,進而也不會阻塞主線程。所以,有些人可能就會將發送短信/郵件以及寫日誌的操作如下方式進行改造。

public async Task<IActionResult> Reg1([FromBody] User user)
{
    _logger.LogInformation("持久化數據開始");
    await Task.Delay(50);
    _logger.LogInformation("持久化結束");
    _ = Task.Run(async () =>
     {
         _logger.LogInformation("發送短信開始");
         await Task.Delay(100);
         _logger.LogInformation("發送短信結束");
         _logger.LogInformation("操作日誌開始");
         await _logRepository.Insert(new Log { Txt = "註冊日誌" });
         _logger.LogInformation("操作日誌結束");
     });
    return Ok("註冊成功");
}

然後使用jmeter分別壓測改造前和改造后的接口,結果如下:

有沒有被驚訝到?就這樣一個簡單的改造,吞吐量就提高了三四倍。既然已經提高了三四倍,那為什麼說這是一種錯誤的改造方法嗎?各位看官且往下看。

熟悉.netcore的大佬,應該都知道.netcore的依賴注入的生命周期吧。通常情況下,注入的生命周期包括:Singleton,Scope,Transient。
在以上的流程中,假如寫操作日誌的實例的生命周期是Scope,當在Task中調用Controller獲取到的實例的方法時,因為Task.Run並沒有阻塞主線程,當調用Action return后,當前請求的scope注入的對象會被回收,如果對象被回收之後,Task.Run還未執行完,則會報System.ObjectDisposedException: Cannot access a disposed object. 異常。意思是,不能訪問一個已disposed的對象。正確的做法是使用IServiceScopeFactory創建一個新的作用域,在新的作用域中獲取獲取日誌倉儲服務的實例。這樣就可以避免System.ObjectDisposedException異常了。
改造后的示例代碼如下:

public async Task<IActionResult> Reg1([FromBody] User user)
{
    _logger.LogInformation("持久化數據開始");
    await Task.Delay(50);
    _logger.LogInformation("持久化結束");
    _ = Task.Run(async () =>
    {
        using (var scope = _scopeFactory.CreateScope())
        {
            var sp = scope.ServiceProvider;
            var logRepository = sp.GetService<ILogRepository>();
            _logger.LogInformation("發送短信開始");
            await Task.Delay(100);
            _logger.LogInformation("發送短信結束");

            _logger.LogInformation("操作日誌開始");
            await logRepository.Insert(new Log { Txt = "註冊日誌" });
            _logger.LogInformation("操作日誌結束");
        }
    });
    return Ok("註冊成功");
}

雖然得到了正解,但上述的代碼着實有點多,如果一個項目有多個相似的業務場景,就要考慮對CreateScope相關的操作進行封裝。

下面就來一一介紹下筆者覺得實現此業務場景的幾種方案。
1.消息隊列
2.Quartz任務調度組件
3.Hangfire任務調度組件
4.Weshare.TransferJob(推薦)
首先說下消息隊列的方式。準確的說,消息隊列應該是這種場景的最優解決方案,消息隊列的其中一個比較重要的特性就是解耦,從而提高吞吐量。但並不是所有的應用程序都需要上消息隊列。有些業務場景使用消息隊列時,往往會給人一種”殺雞用牛刀”的感覺。

其次Quartz和Hangfire都是任務調度框架,都提供了可實現以上業務場景的邏輯,但Quartz和Hangfire都需要持久化作業數據。雖然Hangfire提供了內存版本,但經過我的測試,發現Hangfire的內存版本特別消耗內存,所以不太推薦使用任務調度框架來實現類似於這樣的業務邏輯。

最後,也就是本文的重點,筆者結合了消息隊列和任務調度的思想,實現了一個輕量級的轉移作業到後台執行的組件。此組件完美的解決了Scope生命周期實例獲取的問題,一行代碼將不需要等待的操作轉移到後台線程執行。
接入步驟如下:
1.使用nuget安裝Weshare.TransferJob
2.在Stratup中注入服務。

services.AddTransferJob();

3.通過構造函數或其他方法獲取到IBackgroundRunService的實例。
4.調用實例的Transfer方法將作業轉移到後台線程。

_backgroundRunService.Transfer(log=>log.Insert(new Log(){Txt = "註冊日誌"}));

就是這麼簡單的實現了這樣的業務場景,不僅簡化了代碼,而且大大提高了系統的吞吐量。

下面再來一起分析下Weshare.TransferJob的核心代碼(畢竟文章要點題)。各位器宇不凡的看官請繼續往下看。
下面的代碼是AddTransferJob方法的實現:

public static IServiceCollection AddTransferJob(this IServiceCollection services)
{
    services.AddSingleton<IBackgroundRunService, BackgroundRunService>();
    services.AddHostedService<TransferJobHostedService>();
    return services;
}

聰明”絕頂”的各位看官應該已經發現上述代碼的關鍵所在。是的, 你沒有看錯,此組件的就是利用.net core提供的HostedService在後台執行被轉移的作業的。
我們再來一起看看TransferJobHostedService的代碼:

public class TransferJobHostedService:BackgroundService
{
    private IBackgroundRunService _runService;
    public TransferJobHostedService(IBackgroundRunService runService)
    {
        _runService = runService;
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await _runService.Execute(stoppingToken);
        }
    }
}

這個類的代碼也很簡單,重寫了BackgroundService類的ExecuteAsync,循環調用IBackgroundRunService實例的Execute方法。所以,最最關鍵的代碼是IBackgroundRunService的實現類中。
詳細代碼如下:

public class BackgroundRunService : IBackgroundRunService
{
    private readonly SemaphoreSlim _slim;
    private readonly ConcurrentQueue<LambdaExpression> queue;
    private ILogger<BackgroundRunService> _logger;
    private readonly IServiceProvider _serviceProvider;
    public BackgroundRunService(ILogger<BackgroundRunService> logger, IServiceProvider serviceProvider)
    {
        _slim = new SemaphoreSlim(1);
        _logger = logger;
        _serviceProvider = serviceProvider;
        queue = new ConcurrentQueue<LambdaExpression>();
    }
    public async Task Execute(CancellationToken cancellationToken)
    {
        try
        {
            await _slim.WaitAsync(cancellationToken);
            if (queue.TryDequeue(out var job))
            {
                using (var scope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
                {
                    var action = job.Compile();
                    var isTask = action.Method.ReturnType == typeof(Task);
                    var parameters = job.Parameters;
                    var pars = new List<object>();
                    if (parameters.Any())
                    {
                        var type = parameters[0].Type;
                        var param = scope.ServiceProvider.GetRequiredService(type);
                        pars.Add(param);
                    }
                    if (isTask)
                    {
                        await (Task)action.DynamicInvoke(pars.ToArray());
                    }
                    else
                    {
                        action.DynamicInvoke(pars.ToArray());
                    }
                }
            }
        }
        catch (Exception e)
        {
            _logger.LogError(e.ToString());
        }
    }
    public void Transfer<T>(Expression<Func<T, Task>> expression)
    {
        queue.Enqueue(expression);
        _slim.Release();
    }
    public void Transfer(Expression<Action> expression)
    {
        queue.Enqueue(expression);
        _slim.Release();
    }
}

納尼?嫌代碼多看不懂?那咱們一起來剖析下吧。
首先,此類有三個較重要的私有變量,對應的類型分別是SemaphoreSlim, ConcurrentQueue ,IServiceProvider。
其中SemaphoreSlim是為了控制後台作業執行的順序的,在構造函數中初始化了此對象的信號量為1,表示在後台服務的ExecuteAsync方法的循環中每次只能有一個作業執行。
ConcurrentQueue 的對象是用來存儲被轉移到後台服務執行的作業的邏輯,所以使用LambdaExpression作為隊列的類型。
IServiceProvider是為了解決依賴注入的生命周期的。

然後在Execute方法中,第一行代碼如下:

await _slim.WaitAsync(cancellationToken);

作用是等待一個信號量,當沒有可用的信號量時,會阻塞線程的執行,這樣在後台服務的ExecuteAsync方法的死循環就不會一直執行下去,只有獲取到信號量才會繼續執行。
當獲取到信號量后,則說明有新的作業等待執行,所以此時則需要從隊列中讀出要執行的LambdaExpression表達式,創建一個新的Scope后,編譯此表達式樹,判斷返回類型,獲取泛型的具體類型,最後獲取到泛型對應的實例,執行對應的方法。

另外,Transfer方法就是暴露給調用者的方法,用於將表達式樹寫到隊列中,同時釋放信號量。

到此為止,Weshare.TransferJob的實現原理已分析完畢,由於此組件的原理只是將任務轉移到後台進行執行,所以並不是適合對事務有要求的場景。正如本文開頭所假設的場景,TransferJob最適合的場景還是那些和主操作關聯性較低的、失敗或成功並不會影響業務的正常運行。
同時,此組件的定位就是小而美,像延遲執行、定時執行的功能在最初的規劃中其實是有的,後來發現這些功能quartz已經有了,所以沒必要重複造這樣的輪子。
後期會根據使用場景,嘗試加入異常重試機制,以及異常通知回調機制。

最後,不知道有沒有較真的看官想計算下代碼量是否超過120行。
為了證明我不是標題黨,現將此組件進行開源,地址是:
https://github.com/fuluteam/WeShare.TransferJob

橋豆麻袋,筆者辛苦敲的代碼,難道各位看官想白嫖嗎? 點個贊再走唄。點完贊還有力氣的話,如果git上能點個star的話,那也是最好不過的。小生這廂先行謝過。

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

分佈式鎖的一些理解

 在多線程併發的情況下,單個節點內的線程安全可以通過synchronized關鍵字和Lock接口來保證。

synchronized和lock的區別

  1. Lock是一個接口,是基於在語言層面實現的鎖,而synchronized是Java中的關鍵字,是基於JVM實現的內置鎖,Java中的每一個對象都可以使用synchronized添加鎖。

  2. synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

  3. Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;

  4. Lock可以提高多個線程進行讀操作的效率。(可以通過readwritelock實現讀寫分離,一個用來獲取讀鎖,一個用來獲取寫鎖。)

  當開發的應用程序處於一個分佈式的集群環境中,涉及到多節點,多進程共同完成時,如何保證線程的執行順序是正確的。比如在高併發的情況下,很多企業都會使用Nginx反向代理服務器實現負載均衡的目的,這個時候很多請求會被分配到不同的Server上,一旦這些請求涉及到對統一資源進行修改操作時,就會出現問題,這個時候在分佈式系統中就需要一個全局鎖實現多個線程(不同進程中的線程)之間的同步。

  常見的處理辦法有三種:數據庫、緩存、分佈式協調系統。數據庫和緩存是比較常用的,但是分佈式協調系統是不常用的。

  常用的分佈式鎖的實現包含:

      Redis分佈式鎖Zookeeper分佈式鎖Memcached

基於 Redis 做分佈式鎖

 Redis提供的三種方法:

(1)鎖 SETNX:只在鍵 key 不存在的情況下, 將鍵 key 的值設置為 value 。若鍵 key 已經存在, 則 SETNX 命令不做任何動作。SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。命令在設置成功時返回 1 , 設置失敗時返回 0

redis> SETNX job "programmer"    # job 設置成功
(integer) 1

redis> SETNX job "code-farmer"   # 嘗試覆蓋 job ,失敗

(2)解鎖 DEL:刪除給定的一個或多個 key

(3)鎖超時 EXPIRE: 為給定 key 設置生存時間,當 key 過期時(生存時間為 0 ),它會被自動刪除。

  每次當一個節點想要去操作臨界資源的時候,我們可以通過redis來的鍵值對來標記一把鎖,每一進程首先通過Redis訪問同一個key,對於每一個進程來說,如果該key不存在,則該線程可以獲取鎖,將該鍵值對寫入redis,如果存在,則說明鎖已經被其他進程所佔用。具體邏輯的偽代碼如下:

try{
	if(SETNX(key, 1) == 1){
		//do something ......
	}finally{
	DEL(key);
}

  但是此時,又會出現問題,因為SETNX和DEL操作並不是原子操作,如果程序在執行完SETNX后,而並沒有執行EXPIRE就已經宕機了,這樣一來,原先的問題依然存在,整個系統都將被阻塞。

  幸虧Redis又提供了SET key value timeout NX方法,可以以原子操作的方式完成SETNX和EXPIRE的操作。此時只需如下操作即可。

try{
	if(SET(key, 1, 30, timeout, NX) == 1){
		//do something ......
	}
}finally{
	DEL(key);
}

  解決了原子操作,仍然還有一點需要注意,例如,A節點的進程獲取到鎖的時候,A進程可能執行的很慢,在do something未完成的情況下,30秒的時間片已經使用完,此時會將該key給深處掉,此時B進程發現這個key不存在,則去訪問,並成功的獲取到鎖,開始執行do something,此時A線程恰好執行到DEL(key),會將B的key刪除掉,此時相當於B線程在訪問沒有加鎖的臨界資源,而其餘進程都有機會同時去操作這個臨界資源,會造成一些錯誤的結果。對於該問題的解決辦法是進程在刪除key之前可以做一個判斷,驗證當前的鎖是不是本進程加的鎖。

String threadId = Thread.currentThread().getId()
try{
	if(SET(key, threadId, 30, timeout, NX) == 1){
		//do something ......
	}
}finally{
    if(threadId.equals(redisClient.get(key))){
        DEL(key);
    }
}

   上面的改進雖然解決鎖被不同的進程釋放的危險,但並沒有解決獲取到鎖的進程在指定的時間內未完成do something操作(上面的代碼還有一點小問題,就是判斷操作和釋放鎖是兩個獨立的操作,不具備原子性。假設線程A判斷完確實是自己加的鎖 , 這時還沒del ,這時有效的時間用完了 , 緊接着線程B又馬上搶到了鎖 , 然後線程A才執行del命令 , 就會把B搶到的鎖給誤刪了),使得卡住的進程有可能與後來的進程同時同問臨界資源,而出現問題,因此一旦某個進程無法在超時時間內完成對臨界資源的操作,就需要延長超時的時間。此時可以啟動一個守護進程,監視指定時間內獲取鎖的進程是否完成操作,如果沒有,則添加超時時間,讓程序繼續執行。

String threadId = Thread.currentThread().getId()
try{
	if(SET(key, threadId, 30, timeout, NX) == 1){
		new Thread(){
            @Override
            public void run() {
            	//start Daemon
            }
         }
		//do something ......
	}
}finally{
    if(threadId.equals(redisClient.get(key))){
        DEL(key);
    }
}

  基於以上的分析,基本上可以通過Redis實現一個分佈式鎖,如果我們想提升該分佈式的性能,我們可以對連接資源進行分段處理,將請求均勻的分佈到這些臨界資源段中,比如一個買票系統,我們可以將100張票分為10 部分,每部分包含10張票放在其他的服務節點上,這些請求可以通過Nginx被均勻的分散到這些處理節點上,可以加快對臨界資源的處理。

參考資料

  1. 併發編程的鎖機制:synchronized和lock

  2. B站視頻上一部分講解

  3. 什麼是分佈式鎖?

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

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

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

漢娜颶風肆虐德州 吹倒美墨邊境圍牆

摘錄自2020年7月27日東森國際新聞美國報導

美國德州(Texas)新冠肺炎疫情持續肆虐,周末又遭颶風漢娜(Hanna)侵襲。漢娜是今年第一個颶風,它已經摧毀許多船隻、淹沒街道、造成電力中斷、甚至吹倒一部分美墨邊境圍牆,災情相當嚴重。

據外媒《WDSU News》報導,國家颶風中心(National Hurricane Center)表示,目前颶風漢娜已降為熱帶低氣壓,以每小時超過50英里的風速橫越美墨邊境,並在德州南部和墨西哥東北部的部分地區降下了超過300毫米的豪雨。

州長格雷格·阿博特 (Greg Abbott)於週六(25日)在一場記者會中表示,「任何颶風都是一場巨大的挑戰,但這次的挑戰非常複雜,必且比以往更加嚴峻,因為這場颶風正在席捲著新冠肺炎的其中一個震央。」

土地利用
國際新聞
美國
颶風
災害

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

【其他文章推薦】

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

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

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

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

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

東北印有權有勢「黑手黨」 藉非法伐木撕裂犀鳥棲地

環境資訊中心綜合外電;黃鈺婷 翻譯;林大利 審校;稿源:Mongabay

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

英國首例 寵物貓確診武漢肺炎

摘錄自2020年7月27日中央社報導

英國廣播公司(BBC)報導,英國出現第一例寵物貓確診2019冠狀病毒疾病(COVID-19,武漢肺炎),專家表示這是英國第一起動物確診病例。衛生官員強調,這起案例非常罕見,民眾不需緊張。

據信是遭到確診的飼主傳染,但這不代表病毒可能透過寵物傳播。目前飼主與貓都已經痊癒。英國首席獸醫官密道米斯(Christine Middlemiss)表示:「沒有證據顯示寵物會直接將病毒傳播給人類,我們將持續密切關注,若情況生變,將告知飼主最新守則。」

英格蘭公共衛生署主任陶艾爾(Yvonne Doyle)建議民眾定期清潔雙手,包括在接觸動物前後。若動物接觸患病的人,牠們的毛髮在短期內可能會攜帶病毒。

國際新聞
英國
武漢肺炎
寵物

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

【其他文章推薦】

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

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

※超省錢租車方案

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

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

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

柬埔寨首都擴張摧毀濕地 逾百萬人安全生計堪憂

摘錄自2020年7月27日中央社報導

人權團體今(27日)警告,柬埔寨首都金邊(Phnom Penh)的濕地遭公寓建設和工業活動摧毀,逾100萬人正面臨洪患加劇和失去生計的風險。社運人士在一份報告中表示,包括ING City衛星城在內的開發案,將使1500公頃的東本(Tompoun)濕地面積剩不到1/10,周邊超過1000戶家庭將被迫遷離。金邊市150萬人口當中,也會有數千戶在濕地耕種捕魚的家庭變得窮困。

地方民團組織在報告中寫道:「濕地支撐本地社群的生計,同時在金邊的汙水管理與防洪等方面扮演關鍵角色。」「摧毀濕地潛藏的毀滅性衝擊,可能影響數百萬名柬埔寨人。」斯德哥爾摩環境研究所(Stockholm Environment Institute)曼谷中心的高級研究員阿契爾(Diane Archer)表示,湖泊以及氾濫平原、紅樹林、沼澤等濕地,能夠調節水流、減少洪患、淨化水資源和補充地下水。

根據保育團體野禽與濕地保護基金會(Wildfowl and Wetlands Trust),柬埔寨雖支持國際濕地保護公約,但過去15年來,原有濕地已消失大半。

濕地
生物多樣性
國際新聞
柬埔寨
棲地保育

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

鴻海擴大綠色能源布局 打造越南最大屋頂太陽能系統

摘錄自2020年7月27日經濟日報報導

鴻海集團落實企業社會責任,並強化永續綠色能源布局,相關綠能布局延伸至海外,將在越南廠區屋頂開始安裝太陽能板,打造越南當地最大的屋頂太陽能發電系統。

鴻海集團越南當地規劃,關聯公司將逐步提高太陽能等永續能源採用比重。據說明,越南子公司依據新的購電協議,在越南工廠屋頂上安裝6MW(百萬瓦)太陽能系統發電。

鴻海集團和相關太陽能系統項目開發商簽訂合約,依據相關合作計畫,開發商將在鴻海集團河內附近工廠建設太陽能發電設施。

相關建設計畫到位後,太陽能設施將能滿足鴻海集團越南當地子公司New Wing Interconnect Technology (NWIT)製造業務所需25%能源。

NWIT主管指出,公司目標是達成100%使用潔淨能源,因此和相關開發商合作,目標建立越南最大屋頂太陽能發電系統。

國際新聞
越南
鴻海
太陽能板
太陽屋頂

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

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

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

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

比老司機更會玩の日常

com/x/page/u0353zzxlol。html)據傳,這就是新TIIDA車主的日常。果然“城會玩”,待俺去充個“會員”,咱一起飛。溫馨提示:點擊閱讀原文,預約試駕,馬上成為“會員”。(閱讀原文鏈接如下:http://www。dongfeng-nissan。com。cn/Nissan/car/tiida)。

話說,一群老司機聚在一起能幹什麼?

吃吃?

喝喝?

騷年,敢不敢幹一票“大”的?

↓↓↓↓↓

(視頻鏈接如下:https://v.qq.com/x/page/u0353zzxlol.html)

據傳,

這就是新TIIDA車主的日常。

果然“城會玩”,

待俺去充個“會員”,

咱一起飛。

溫馨提示:點擊閱讀原文,預約試駕,馬上成為“會員”。

(閱讀原文鏈接如下:http://www.dongfeng-nissan.com.cn/Nissan/car/tiida)本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

2016重磅轎車盤點 自主雄起/合資緊張?

無論如何,2016年都將要過去,而2016年我們看到了帝豪GL與艾瑞澤5這兩款代表自主品牌實力的力作,尤其是帝豪GL對於整個自主品牌都是意義重大,帝豪GL可以說開拓了一個新的細分市場,尺寸介於A級車與B級車之間,價格卻比緊湊型車型高不了多少,這樣的產品力表現值得讚歎。

這裏小編團隊特地舉行了一次盛大的年度討論,目的就是選出2016年最值得推薦的年度轎車/年度SUV以及2016年自主品牌的新技術。而經過了長時間的激烈討論之後我們終於確定了5款年度轎車,它們都具有強大的產品力,可以說對車市有不小的影響,雖然有些車型的銷量不那麼好看但是實力無需否認,那麼我們一起看看是什麼車型能夠成為年度推薦轎車吧。

無論如何,2016年都將要過去,而2016年我們看到了帝豪GL與艾瑞澤5這兩款代表自主品牌實力的力作,尤其是帝豪GL對於整個自主品牌都是意義重大,帝豪GL可以說開拓了一個新的細分市場,尺寸介於A級車與B級車之間,價格卻比緊湊型車型高不了多少,這樣的產品力表現值得讚歎。

而在合資車方面科沃茲的出現可以說是給合資三廂入門車型帶來了新鮮血液,不錯的產品力表現以及定位能夠給自主車帶來不小的衝擊,科沃茲上市開始就成為爆款車型也是實力的印證,混動雅閣的出現攪動了新能源市場,可以說是混動市場的一顆重磅炸彈,加之漂亮的外觀優秀的內飾,混動雅閣讓人難以拒絕。

最後就是沃爾沃S90了,這款車型依靠漂亮的設計吸引了不少人的目光,而最終價格也是讓人震驚,相信離大賣也不遠了,雖然2016年整个中國車市的重心全都放在了SUV方面,無論是開發的新車型數量還是現有SUV車型的銷量都是節節拔高,但是依然不少人選擇緊湊型轎車,緊湊型轎車的銷量佔比也是十分高,自主轎車在A到B級的產品力補充得不錯,但是B級以上還需要品牌力等更多的補充,2017年即將到來,轎車市場能否迎來更大的輝煌呢?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

奔馳最便宜的小轎車到來,價格可能比2.4雅閣還便宜?

奔馳Z級定位小型車,競爭對手鎖定奧迪A1以及MINI,從造型上來看奔馳Z級還是比較的有奔馳家族風格的,大尺寸的輪轂和小巧的車身形成鮮明對比,運動風格比較強烈。從前臉造型上看Z級的造型和奔馳GLC有着比較高的相似度,全LED大燈的造型也和奔馳高端車型幾乎一致,大燈尺寸和進氣格柵都十分大,加上GLC元素的使用使得前臉還是比較有氣勢的。

奔馳這個品牌在中國市場深耕多年早已深入人心,一說起豪車大家都會想到奔馳寶馬,但是奔馳給大多數人的印象一直是價格昂貴高高在上的,比如售價過百萬的奔馳S、全尺寸SUV奔馳GLS等,但奔馳不止有這些車。

↑↑↑目前能夠買到的最便宜的三廂轎車CLA指導價為26.60-37.80萬

↑↑↑目前能夠買到最便宜奔馳兩廂轎車奔馳A級指導價為指導價:23.40-36.00萬

你以為這就是奔馳最便宜車型的價格了嗎?當然不是,外媒繪製了一張奔馳Z級的假想圖,目前奔馳A級以及奔馳CLA都屬於緊湊型車型,而奔馳目前並沒有小型車,而Z級的出現即將填補奔馳在這一市場的空白。

奔馳Z級定位小型車,競爭對手鎖定奧迪A1以及MINI,從造型上來看奔馳Z級還是比較的有奔馳家族風格的,大尺寸的輪轂和小巧的車身形成鮮明對比,運動風格比較強烈。

從前臉造型上看Z級的造型和奔馳GLC有着比較高的相似度,全LED大燈的造型也和奔馳高端車型幾乎一致,大燈尺寸和進氣格柵都十分大,加上GLC元素的使用使得前臉還是比較有氣勢的。

來到尾部,層次豐富的尾部造型也頗有幾分GLC的味道,排氣管的造型十分有運動感,只是尺寸偏小,尾燈的造型也和奔馳現今的SUV車型設計比較相似,Z級在外觀上和奔馳SUV車系比較接近,因此小編預測未來Z級會衍生出SUV車型或者跨界版,名字就叫GLZ?到時候就是小號的GLC了。

從假想圖看來車頂高度在後排位置下降比較多,小編對於Z級的頭部空間表現表示擔憂。

Z級的出現拉低了奔馳車型的入門門檻,而和奧迪A1以及寶馬MINI對標的話,小編預計Z級的售價在18萬起,這樣的售價也算是對得起觀眾了,當然由於這類車型比較小眾,因此即使上市也會以進口身份銷售,因此希望售價過低還是不太可能。

競爭對手:

奔馳Z級上市后競爭對手主要是奧迪A1、寶馬MINI以及雪鐵龍DS3,相比之下A1有着奧迪的科技感以及龐大的受眾,DS3比較的怪異能夠贏得一些消費者的喜愛,MINI則是哪個經典造型,十分有個性,與它們相比奔馳Z級的道路還比較長。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※超省錢租車方案

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

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

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