小師妹學JVM之:深入理解JIT和編譯優化-你看不懂系列

目錄

  • 簡介
  • JIT編譯器
  • Tiered Compilation分層編譯
  • OSR(On-Stack Replacement)
  • Deoptimization
  • 常見的編譯優化舉例
    • Inlining內聯
    • Branch Prediction分支預測
    • Loop unswitching
    • Loop unrolling展開
    • Escape analysis逃逸分析
  • 總結

簡介

小師妹已經學完JVM的簡單部分了,接下來要進入的是JVM中比較晦澀難懂的概念,這些概念是那麼的枯燥乏味,甚至還有點惹人討厭,但是要想深入理解JVM,這些概念是必須的,我將會盡量嘗試用簡單的例子來解釋它們,但一定會有人看不懂,沒關係,這個系列本不是給所有人看的。

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

JIT編譯器

小師妹:F師兄,我的基礎已經打牢了嗎?可以進入這麼複雜的內容環節了嗎?

小師妹不試試怎麼知道不行呢?了解點深入內容可以幫助你更好的理解之前的知識。現在我們開始吧。

上次我們在講java程序的處理流程的時候,還記得那通用的幾步吧。

小師妹:當然記得了,編寫源代碼,javac編譯成字節碼,加載到JVM中執行。

對,其實在JVM的執行引擎中,有三個部分:解釋器,JIT編譯器和垃圾回收器。

解釋器會將前面編譯生成的字節碼翻譯成機器語言,因為每次都要翻譯,相當於比直接編譯成機器碼要多了一步,所以java執行起來會比較慢。

為了解決這個問題,JVM引入了JIT(Just-in-Time)編譯器,將熱點代碼編譯成為機器碼。

Tiered Compilation分層編譯

小師妹你知道嗎?在JDK8之前,HotSpot VM又分為三種。分別是 client VM, server VM, 和 minimal VM,分別用在客戶端,服務器,和嵌入式系統。

但是隨着硬件技術的發展,這些硬件上面的限制都不是什麼大事了。所以從JDK8之後,已經不再區分這些VM了,現在統一使用VM的實現來替代他們。

小師妹,你覺得Client VM和Server VM的本質區別在哪一部分呢?

小師妹,編譯成字節碼應該都是使用javac,都是同樣的命令,字節碼上面肯定是一樣的。難點是在執行引擎上面的不同?

說的對,因為Client VM和Server VM的出現,所以在JIT中出現了兩種不同的編譯器,C1 for Client VM, C2 for Server VM。

因為javac的編譯只能做少量的優化,其實大量的動態優化是在JIT中做的。C2相對於C1,其優化的程度更深,更加激進。

為了更好的提升編譯效率,JVM在JDK7中引入了分層編譯Tiered compilation的概念。

對於JIT本身來說,動態編譯是需要佔用用戶內存空間的,有可能會造成較高的延遲。

對於Server服務器來說,因為代碼要服務很多個client,所以磨刀不誤砍柴工,短暫的延遲帶來永久的收益,聽起來是可以接受的。

Server端的JIT編譯也不是立馬進行的,它可能需要收集到足夠多的信息之後,才進行編譯。

而對於Client來說,延遲帶來的性能影響就需要進行考慮了。和Server相比,它只進行了簡單的機器碼的編譯。

為了滿足不同層次的編譯需求,於是引入了分層編譯的概念。

大概來說分層編譯可以分為三層:

  1. 第一層就是禁用C1和C2編譯器,這個時候沒有JIT進行。
  2. 第二層就是只開啟C1編譯器,因為C1編譯器只會進行一些簡單的JIT優化,所以這個可以應對常規情況。
  3. 第三層就是同時開啟C1和C2編譯器。

在JDK7中,你可以使用下面的命令來開啟分層編譯:

-XX:+TieredCompilation

而在JDK8之後,恭喜你,分層編譯已經是默認的選項了,不用再手動開啟。

OSR(On-Stack Replacement)

小師妹:F師兄,你剛剛講到Server的JIT不是立馬就進行編譯的,它會等待一定的時間來搜集所需的信息,那麼代碼不是要從字節碼轉換成機器碼?

對的,這個過程就叫做OSR(On-Stack Replacement)。為什麼叫OSR呢?我們知道JVM的底層實現是一個棧的虛擬機,所以這個替換實際上是一系列的Stack操作。

上圖所示,m1方法從最初的解釋frame變成了後面的compiled frame。

Deoptimization

這個世界是平衡的,有陰就有陽,有優化就有反優化。

小師妹:F師兄,為什麼優化了之後還要反優化呢?這樣對性能不是下降了嗎?

通常來說是這樣的,但是有些特殊的情況下面,確實是需要進行反優化的。

下面是比較常見的情況:

  1. 需要調試的情況

如果代碼正在進行單個步驟的調試,那麼之前被編譯成為機器碼的代碼需要反優化回來,從而能夠調試。

  1. 代碼廢棄的情況

當一個被編譯過的方法,因為種種原因不可用了,這個時候就需要將其反優化。

  1. 優化之前編譯的代碼

有可能出現之前優化過的代碼可能不夠完美,需要重新優化的情況,這種情況下同樣也需要進行反優化。

常見的編譯優化舉例

除了JIT編譯成機器碼之外,JIT還有一下常見的代碼優化方式,我們來一一介紹。

Inlining內聯

舉個例子:

int a = 1;
int b = 2;
int result = add(a, b);
...
public int add(int x, int y) { return x + y; }
int result = a + b; //內聯替換

上面的add方法可以簡單的被替換成為內聯表達式。

Branch Prediction分支預測

通常來說對於條件分支,因為需要有一個if的判斷條件,JVM需要在執行完畢判斷條件,得到返回結果之後,才能夠繼續準備後面的執行代碼,如果有了分支預測,那麼JVM可以提前準備相應的執行代碼,如果分支檢查成功就直接執行,省去了代碼準備的步驟。

比如下面的代碼:

// make an array of random doubles 0..1
double[] bigArray = makeBigArray();
for (int i = 0; i < bigArray.length; i++)
{
 double cur = bigArray[i];
 if (cur > 0.5) { doThis();} else { doThat();}
}

Loop unswitching

如果我們在循環語句裏面添加了if語句,為了提升併發的執行效率,可以將if語句從循環中提取出來:

  int i, w, x[1000], y[1000];
  for (i = 0; i < 1000; i++) {
    x[i] += y[i];
    if (w)
      y[i] = 0;
  }

可以改為下面的方式:

  int i, w, x[1000], y[1000];
  if (w) {
    for (i = 0; i < 1000; i++) {
      x[i] += y[i];
      y[i] = 0;
    }
  } else {
    for (i = 0; i < 1000; i++) {
      x[i] += y[i];
    }
  }

Loop unrolling展開

在循環語句中,因為要不斷的進行跳轉,所以限制了執行的速度,我們可以對循環語句中的邏輯進行適當的展開:

 int x;
 for (x = 0; x < 100; x++)
 {
     delete(x);
 }

轉變為:

 int x; 
 for (x = 0; x < 100; x += 5 )
 {
     delete(x);
     delete(x + 1);
     delete(x + 2);
     delete(x + 3);
     delete(x + 4);
 }

雖然循環體變長了,但是跳轉次數變少了,其實是可以提升執行速度的。

Escape analysis逃逸分析

什麼叫逃逸分析呢?簡單點講就是分析這個線程中的對象,有沒有可能會被其他對象或者線程所訪問,如果有的話,那麼這個對象應該在Heap中分配,這樣才能讓對其他的對象可見。

如果沒有其他的對象訪問,那麼完全可以在stack中分配這個對象,棧上分配肯定比堆上分配要快,因為不用考慮同步的問題。

我們舉個例子:

  public static void main(String[] args) {
    example();
  }
  public static void example() {
    Foo foo = new Foo(); //alloc
    Bar bar = new Bar(); //alloc
    bar.setFoo(foo);
  }
}

class Foo {}

class Bar {
  private Foo foo;
  public void setFoo(Foo foo) {
    this.foo = foo;
  }
}

上面的例子中,setFoo引用了foo對象,如果bar對象是在heap中分配的話,那麼引用的foo對象就逃逸了,也需要被分配在heap空間中。

但是因為bar和foo對象都只是在example方法中調用的,所以,JVM可以分析出來沒有其他的對象需要引用他們,那麼直接在example的方法棧中分配這兩個對象即可。

逃逸分析還有一個作用就是lock coarsening。

為了在多線程環境中保證資源的有序訪問,JVM引入了鎖的概念,雖然鎖可以保證多線程的有序執行,但是如果實在單線程環境中呢?是不是還需要一直使用鎖呢?

比如下面的例子:

public String getNames() {
     Vector<String> v = new Vector<>();
     v.add("Me");
     v.add("You");
     v.add("Her");
     return v.toString();
}

Vector是一個同步對象,如果是在單線程環境中,這個同步鎖是沒有意義的,因此在JDK6之後,鎖只在被需要的時候才會使用。

這樣就能提升程序的執行效率。

總結

本文介紹了JIT的原理和一些基本的優化方式。後面我們會繼續探索JIT和JVM的秘密,敬請期待。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-jit-in-detail/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準

.Net Core微服務入門全紀錄(四)——Ocelot-API網關(上)

前言

上一篇【.Net Core微服務入門全紀錄(三)——Consul-服務註冊與發現(下)】已經使用Consul完成了服務的註冊與發現,實際中光有服務註冊與發現往往是不夠的,我們需要一個統一的入口來連接客戶端與服務。

Ocelot

官網:https://ocelot.readthedocs.io/
Ocelot正是為.Net微服務體系提供一個統一的入口點,稱為:Gateway(網關)。

  • 上手Ocelot:

首先創建一個空的asp.net core web項目。

注意ocelot.json是我們添加的Ocelot的配置文件,記得設置生成時複製到輸出目錄。ocelot.json的文件名不是固定的,可以自己定義。

NuGet安裝一下Ocelot:

只需簡單的修改幾處默認代碼:
Program.cs:

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    config.AddJsonFile("ocelot.json");
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

Startup.cs:

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            //添加ocelot服務
            services.AddOcelot();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //設置Ocelot中間件
            app.UseOcelot().Wait();
        }
    }

ocelot.json:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/products",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 9050
        },
        {
          "Host": "localhost",
          "Port": 9051
        },
        {
          "Host": "localhost",
          "Port": 9052
        }
      ],
      "UpstreamPathTemplate": "/products",
      "UpstreamHttpMethod": [
        "Get"
      ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //負載均衡,輪詢機制 LeastConnection/RoundRobin/NoLoadBalancer/CookieStickySessions
      }
    },
    {
      "DownstreamPathTemplate": "/orders",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 9060
        },
        {
          "Host": "localhost",
          "Port": 9061
        },
        {
          "Host": "localhost",
          "Port": 9062
        }
      ],
      "UpstreamPathTemplate": "/orders",
      "UpstreamHttpMethod": [
        "Get"
      ],
      "LoadBalancerOptions": {
        "Type": "RoundRobin" //負載均衡,輪詢機制 LeastConnection/RoundRobin/NoLoadBalancer/CookieStickySessions
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:9070"
  }
}

我們先暫時忽略Consul,將服務實例的地址都寫在配置文件中。要知道Consul、Ocelot等組件都是可以獨立存在的。
配置文件中的Routes節點用來配置路由,Downstream代表下游,也就是服務實例,Upstream代表上游,也就是客戶端。我們的路徑比較簡單,只有/products、/orders,路徑中如果有不固定參數則使用{}匹配。我們這個配置的意思呢就是客戶端訪問網關的/orders、/products,網關會轉發給服務實例的/orders、/products,注意這個上游的路徑不一定要和下游一致,比如上游路徑可以配置成/api/orders,/xxx都可以。
LoadBalancerOptions節點用來配置負載均衡,Ocelot內置了 LeastConnection、RoundRobin、NoLoadBalancer、CookieStickySessions 4種負載均衡策略。
BaseUrl節點就是配置我們ocelot網關將要運行的地址。

  • 運行gateway:

目前不考慮網關集群,就不放在docker里了。直接控制台執行:`dotnet Ocelot.APIGateway.dll –urls=”http://*:9070″

用瀏覽器測試一下:

測試正常,我們通過網關可以正常的訪問到服務實例。

  • 接下來繼續改造客戶端代碼:

因為改動太多就直接新建一個GatewayServiceHelper來做。
GatewayServiceHelper:

    /// <summary>
    /// 通過gateway調用服務
    /// </summary>
    public class GatewayServiceHelper : IServiceHelper
    {
        public async Task<string> GetOrder()
        {
            var Client = new RestClient("http://localhost:9070");
            var request = new RestRequest("/orders", Method.GET);

            var response = await Client.ExecuteAsync(request);
            return response.Content;
        }

        public async Task<string> GetProduct()
        {
            var Client = new RestClient("http://localhost:9070");
            var request = new RestRequest("/products", Method.GET);

            var response = await Client.ExecuteAsync(request);
            return response.Content;
        }

        public void GetServices()
        {
            throw new NotImplementedException();
        }
    }

然後在Startup中修改一下注入的類型,別的就不用改了,這就是依賴注入的好處之一。。。
Startup.ConfigureServices():

//注入IServiceHelper
//services.AddSingleton<IServiceHelper, ServiceHelper>();
            
//注入IServiceHelper
services.AddSingleton<IServiceHelper, GatewayServiceHelper>();

Startup.Configure():

//程序啟動時 獲取服務列表
//serviceHelper.GetServices();

運行客戶端測試:

好了,現在客戶端對服務的調用都通過網關進行中轉,客戶端再也不用去關心那一堆服務實例的地址,只需要知道網關地址就可以了。另外,服務端也避免了服務地址直接暴露給客戶端。這樣做對客戶端,服務都非常友好。

至於我們的api網關呢,又要說到服務發現的問題了。目前我們的服務地址是寫在ocelot.json配置文件里的,當然這種做法在服務實例不經常變化的情況下是沒有問題的,一旦服務變化,需要人為的修改配置文件,這又顯得不太合理了。

當然,強大的Ocelot為我們提供了服務發現的方案。

代碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo

未完待續…

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

【其他文章推薦】

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

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

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

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

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

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

深入理解 EF Core:EF Core 讀取數據時發生了什麼?

閱讀本文大概需要 11 分鐘。

原文:https://bit.ly/2UMiDLb
作者:Jon P Smith
翻譯:王亮
聲明:我翻譯技術文章不是逐句翻譯的,而是根據我自己的理解來表述的。其中可能會去除一些本人實在不知道如何組織但又不影響理解的句子。

本文將為你詳細描繪 EF Core 從數據庫中讀取數據的“幕後”視圖。我將揭開兩種數據庫讀取方式的面紗:一個是普通的查詢,另一個是使用 AsNoTracking 方法的非跟蹤查詢。我還將通過一個實驗來演示我是如何解決我的一個客戶遇到的性能問題。

我假設你對 EF Core 已經有了一定的認識,但在深入學習之前,我們先來了解一下如何使用 EF Core,以確保我們已經掌握了一些基本知識。這是一個“深入研究”的課題,所以我準備大量的技術細節,希望我的描述方式你能理解。

本文是“深入理解 EF Core”系列中的第一篇。以下是本系列文章列表:

  • 當 EF Core 從數據庫讀取數據時發生了什麼?(本文)
  • 當 EF Core 寫入數據到數據庫時發生了什麼?(敬請期待)

概要

  • EF Core 有兩種方法從數據庫中讀取數據(也稱為查詢):普通 LINQ 查詢和包含 AsNoTracking 方法的非跟蹤 LINQ 查詢。
  • 這兩種方法查詢的返回類(被稱為實體類),它連接的其它的實體類(即所謂的導航屬性)也被同時加載,但這兩種法如何連接及連接的內容是不一樣的。
  • 普通查詢接受的是 DbContext 執行讀取時所有數據的副本——此時的實體類稱為被跟蹤。這允許加載的實體類參与數據庫的更新操作。
  • 普通查詢還會有一些其它的複雜底層實現,稱為關係修補(fixup),用於描述讀入的實體類和其他被跟蹤實體之間的連接關係。
  • AsNoTracked 非跟蹤查詢沒有副本,所以它沒有被跟蹤——這意味着它比普通查詢更快。這也意味着它不會用於數據庫的寫操作。
  • 最後,我將展示 EF Core 普通查詢中一個鮮為人知的特性,以此作為示例,說明通過導航屬性連接實體類的關係是多麼智能。

EF Core 如何讀取數據庫數據

提示:如果你已經對 EF Core 有一定的認識,那麼你可以跳過這一節,這部分只是一個如何讀取數據庫的例子。

為了能讓你更好地理解,我先描述一個數據庫結構,然後再給出一個簡單的數據庫讀取示例。下面是一些基本表的結構和它們之間的關係。

這些表被映射到具有類似名稱的類,例如 Book、BookAuthor、Author,這些類的屬性名稱與表的字段名稱相同。由於篇幅有限,我不打算展開來講這些類,但您可以在我的 GitHub 倉庫[1]中查看這些類。

EF Core 讀取數據庫需要下面五部分:

  1. 數據庫服務器,如 SQL server, Sqlite, PostgreSQL 等。
  2. 具有數據的數據庫。
  3. 映射到數據表的類(稱為實體類)。
  4. 一個繼承 DbContext 的類,該類包含 EF Core 的配置。
  5. 最後,從數據庫讀取數據的命令。

下面的單元測試代碼來自我的 GitHub 創庫[2],展示了一個簡單的示例,它從現有數據庫中讀取 4 個 Book 實體及其關聯的 BookAuthor 和 Authors 實體。

倉庫地址:https://bit.ly/2Yza7QQ

[Fact]
public void TestBookCountAuthorsOk()
{
    //SETUP
    var options = SqliteInMemory.CreateOptions<EfCoreContext>();
    //code to set up the database with four books, two with the same Author
    using (var context = new EfCoreContext(options))
    {
        //ATTEMPT
        var books = context.Books
            .Include(r => r.AuthorsLink)
            .ThenInclude(r => r.Author)
            .ToList();

        //VERIFY
        books.Count.ShouldEqual(4);
        books.SelectMany(x => x.AuthorsLink.Select(y => y.Author))
            .Distinct().Count().ShouldEqual(3);
    }
}

現在,如果我們將單元測試代碼對應到上面的 5 部分,結果是這樣的:

  1. 數據庫服務器——第 5 行:我選擇了一個 Sqlite 數據庫服務器,在本例中是 SqliteInMemory.CreateOptions 方法,它使用我的一個 NuGet 包 EfCore.TestSupport 創建了一個內存數據庫(內存中的數據庫對於單元測試非常有用,因為你可以為這個測試建立一個新的空數據庫)。
  2. 具有數據的數據庫——第 6 行:我將在下一篇文章介紹數據是如何寫入數據庫的,現在假設有一個數據庫包含 4 本書信息,其中兩本書的作者是同一個人。
  3. 實體類——代碼里這裏沒有展示,但是你可以在這裏查看這些類[1]。其中有一個 Books 實體類,通過一個名為 BookAuhor 的實體類多對多關聯 Authors 實體類。
  4. 一個繼承 DbContext 的類——第 7 行:EfCoreContext 類繼承了 DbContext 類並配置了從類到數據庫的映射關係(你可以在我的 GitHub 倉庫[3] 中查看該類)。
  5. 從數據庫讀取數據的命令——第 10 到 13 行,這是一個查詢:
    • 第 10 行 — context 為 EfCoreContext 的實例,通過它訪問你的數據庫,.Books 表示您希望訪問 Books 表。
    • 第 11 行 — Include 被稱為貪婪加載,它告訴 EF Core 當它加載 Books 時,也應該加載關聯到的所有 BookAuthor 實體類。
    • 第 12 行 — ThenInclude 是繼續貪婪加載,它告訴 EF Core 當它加載一個 BookAuthor 時,它也應該加載關聯到該 BookAuthor 的 Author 實體類。

所有這一切查詢出來是一個結果集,其中有普通屬性,像 Books 的 Title 屬性;有關聯實體類的導航屬性,像 Books 的 AuthorsLink 屬性。

這個示例稱為查詢或讀取,也是四種數據庫訪問類型之一,即 CRUD(新增、讀取、更新和刪除)。我將在下一篇文章中介紹新增和更新。

EF Core 如何表示讀取的數據

當你查詢數據庫時,EF Core 會將數據庫返回的數據轉換為實體類並填充導航屬性的值。在本節中,我們將研究兩種類型的查詢步驟——普通查詢(即沒有 AsNoTracking 方法,也稱為讀寫查詢)和添加了 AsNoTracking 方法的非跟蹤查詢(稱為只讀查詢)。

我們先來看一下最初 LINQ 語句是如何轉換成數據庫相應的查詢命令然後返回數據的。對於我們將要看到的兩種類型的查詢來說,這是很常見的操作。關於查詢的第一部分,請參見下圖。

有一些非常複雜的代碼將你的 LINQ 轉換為數據庫查詢命令,但這些內部細節我們不必關心。如果你的 LINQ 不能被翻譯,你會從 EF Core 得到一個異常消息,其中包含類似“不能被翻譯”的描述詞語。此外,當數據返回時,像 Value Converters[4] 這樣的特性可能會調整數據。

本節展示了查詢的第一部分,其中 LINQ 被轉換為數據庫命令並返回所有正確的值。現在我們來看查詢的第二部分,在這裏 EF Core 獲取返回值並將它們轉換為實體類的實例,並填充導航屬性。我們將分別看看兩種類型的查詢。

1. 普通查詢(讀寫查詢)

普通查詢讀取數據的方式可以修改數據並更新到數據庫,這就是我將其稱為讀寫查詢的原因。它不會自動更新數據(請參閱下一篇文章,了解如何寫入數據庫)。如果你要更新數據,你的查詢必須是讀寫查詢。

我在介紹中給出的示例執行的是一個普通讀寫查詢,讀取帶有 AuthorsLink 實例的示例。下面是該示例的查詢部分的代碼:

var books = context.Books
    .Include(r => r.AuthorsLink)
    .ThenInclude(r => r.Author)
    .ToList();

然後 EF Core 通過三個步驟將這些值轉換並填充含有導航屬性的實體類。下圖显示了這三個步驟以及生成的實體類及其導航屬性的實體類。

讓我們來分析一下這三個步驟:

  1. 創建類並填充數據。它接受數據庫返回的值,並填充非導航(稱為標量)屬性、字段等。在 Book 實體類中,是 BookId(主鍵)、Title 等屬性——參見上圖左下角淺藍色矩形。
  2. 修補關聯關係。首先是填入主鍵和外鍵的信息,它們定義如何相互關聯數據。然後,EF Core 使用這些鍵設置實體類之間的導航屬性(如圖中藍色粗線所示)。這個關係的修補所需的信息不僅是查詢讀入的實體類,它還會查看 DbContext 中跟蹤的每個實體,並填充導航屬性。這是一個強大的功能,但你的被跟蹤實體越多,所需消耗時間也越多——這就是為什麼需要 AsNoTracking 來實現更快的查詢。
  3. 創建跟蹤快照。跟蹤快照是返回給用戶的實體類的一個副本,加上它所隱藏的與每個實體類的關聯關係——若一個實體處於被跟蹤狀態,這意味着它將會發生修改並會寫入到數據庫中。

2. 非跟蹤查詢(只讀查詢)

非跟蹤查詢,即使用 AsNoTracking 方法的查詢,是一個只讀查詢。這意味着,當 SaveChanges 方法被調用時,你讀取的任何內容都不會被寫入數據庫。非跟蹤查詢的查詢效率更高,在下一節中,我將介紹非跟蹤查詢以及與普通查詢的其他區別。

在前文的示例之後,我修改了查詢代碼,添加了下面的 AsNoTracking 方法(請看第 2 行):

var books = context.Books
    .AsNoTracking()
    .Include(r => r.AuthorsLink)
    .ThenInclude(r => r.Author)
    .ToList();

這裏的 LINQ 查詢只有上面的普通查詢的前兩個步驟(沒有第三個步驟)。下圖显示了 AsNoTracking 查詢的步驟。

步驟如下:

  1. 創建類並填充數據。它接受數據庫返回的值,並填充非導航(稱為標量)屬性、字段等。在 Book 實體類中,是 BookId(主鍵)、Title 等屬性——參見上圖左下角淺藍色矩形。
  2. 修補關聯關係。首先是填入主鍵和外鍵的信息,它們定義如何相互關聯數據。然後,EF Core 使用這些鍵設置實體類之間的導航屬性(如圖中藍色粗線所示)。這個關係的修補所需的信息不僅是查詢讀入的實體類,它還會查看 DbContext 中跟蹤的每個實體,並填充導航屬性。這是一個強大的功能,但你的被跟蹤實體越多,所需消耗時間也越多——這就是為什麼需要 AsNoTracking 來實現更快的查詢。

普通查詢和非跟蹤查詢的區別

現在讓我們比較這兩種查詢比較明顯的區別。

  1. 非跟蹤查詢查詢的性能更好。使用非跟蹤查詢查詢的主要原因是性能。非跟蹤查詢查詢表現為:

    • 稍微快一點,使用的內存稍微少一點,因為它不需要創建跟蹤快照。
    • 避免沒有必要的跟蹤快照可以提高 SaveChanges 的性能,因為它不必檢查跟蹤快照以查找更改。
    • 稍微快一點,因為修補關聯關係時沒有所謂的身份解析。這就是為什麼你會得到兩個具有相同數據的 Author 實例。
  2. 非跟蹤查詢修補關聯關係時只鏈接查詢中的實體。在普通查詢中,我已經說過修補關聯關係時連接的是查詢中的實體和當前跟蹤的實體,但是非跟蹤查詢只修補查詢中的實體關係。

  3. 非跟蹤查詢並不總是代表數據庫關係。這兩種類型查詢之間的關係修補的另一個區別是,非跟蹤查詢關係修補更快,它不需要標識的解析。這可以為數據庫中的同一行生成多個實例——見上圖右下角藍色的 Author 實體和註釋。如果只是向用戶显示數據,那麼這種差異並不重要,但是如果具有業務邏輯,那麼多個實例不能正確反映數據的結構,就可能會有問題。

對層級數據有用的關係修補特性

關聯關係修補的步驟是非常智能的,特別是在普通查詢中。下面我想向你展示我是如何利用關係修補的特性來解決一個客戶項目中的性能問題的。

我曾在一家公司工作,那裡的許多數據處理都是層次化結構的,即數據具有一系列深度不確定的關聯關係。問題是我必須先解析整個層次結構,然後才能呈現這些數據。我最初是通過貪婪的方式加載前兩個層級,然後顯式地加載更深的層級來實現這一點的。它可以工作,但是性能非常慢,並且數據庫因大量單數據庫訪問而超載。

這不得不讓我思考解決辦法,如果普通查詢的關係修補那麼智能的話,它能幫助我提高查詢的性能嗎?它可以!讓我給你舉一個公司員工的例子。下圖显示了我們想要加載的公司的層次結構。

你可以接龍式地使用 .Include(x => x.WorksForMe).ThenInclude(x => x.WorksForMe)… 等等來加載所需的層級信息,但結果是一個 .Include(x => x.WorksForMe) 就夠了。因為 EF Core 的關係修補為你做了剩下的事情,這一點很驚奇,但也很有用。

例如,如果我想查詢角色為 Development 的所有員工(每個員工都有一個名為 WhatTheyDo 的屬性和名為 Role 的屬性,該 Role 包含他們工作的部門),我可以這樣編寫代碼:

var devDept = context.Employees
    .Include(x => x.WorksFromMe)
    .Where(x => x.WhatTheyDo.HasFlag(Roles.Development))
    .ToList();

這將創建一個查詢,用於加載角色為 Development 的所有員工,並且在員工實體類上修補與 WorksFoMe 導航屬性(集合)和 Manager 導航屬性(單個)的關係。通過只執行一個查詢,既提高了查詢花費的時間,又減少了數據庫服務器上的負載。

總結

你已經看到了兩種類型的查詢,我稱之為 a)普通的讀寫查詢,和 b) 非跟蹤的只讀查詢。對於每一種查詢類型,我都向你展示了 EF Core “幕後”是如何讀取數據並展示的。他們工作方式的不同也表現出他們的優勢和劣勢。

非跟蹤查詢是只讀查詢的解決方案,因為它比普通讀寫查詢更快。但是您應該記住關係修補的機制,它可以在數據庫只有一個關係的情況下創建類的多個實例。

普通的讀寫查詢是查詢跟蹤實體的解決方案,這意味着你可以在創建、更新和刪除數據時使用它們。普通的讀寫查詢確實會佔用更多的時間和內存資源,但是有一些有用的特性,比如自動鏈接到其他被跟蹤的實體類實例。

我希望這篇文章對您有用。祝你編程快樂!

[1]. https://bit.ly/2MXK3ZY
[2]. https://bit.ly/2Yza7QQ
[3]. https://bit.ly/2Y0UORO
[4]. https://bit.ly/2YEyg8j

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

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

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

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

Spring Cloud Alibaba系列(四)使用gateway作為服務網關

什麼是網關

在微服務架構里,服務的粒度被進一步細分,各個業務服務可以被獨立的設計、開發、測試、部署和管理。這時,各個獨立部署單元可以用不同的開發測試團隊維護,可以使用不同的編程語言和技術平台進行設計,這就要求必須使用一種語言和平台無關的服務協議作為各個單元間的通訊方式。

換句話說就是網關為所有的請求提供了統一的入口,方便我們對服務請求和響應做統一管理。

為什麼要用網關

API 網關是一個處於應用程序或服務(提供 REST API 接口服務)之前的系統,用來管理授權、訪問控制和流量限制等,這樣 REST API 接口服務就被 API 網關保護起來,對所有的調用者透明。

什麼是gateway

Spring Cloud Gateway是Spring官方基於Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的網關,Spring Cloud Gateway旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式。Spring Cloud Gateway作為Spring Cloud生態系中的網關,目標是替代ZUUL,其不僅提供統一的路由方式,並且基於Filter鏈的方式提供了網關基本的功能,例如:安全,監控/埋點,和限流等。

gateway工作原理

客戶端向Spring Cloud網關發出請求。如果網關處理程序映射確定請求與路由匹配,則將其發送到網關Web處理程序。該處理程序運行通過特定於請求的過濾器鏈發送請求。過濾器由虛線分隔的原因是,過濾器可以在發送代理請求之前或之後執行邏輯。執行所有“前置”過濾器邏輯,然後發出代理請求。發出代理請求后,將執行“后”過濾器邏輯。

路由規則

路由和過濾器是gateway中非常重要的兩個概念,gateway本身提供了非常豐富的路由規則和多種過濾器來適配我們的需求。gateway提供了11種路由規則,分別是:

  • 後置路由謂詞工廠

    該謂詞匹配在當前日期時間之後發生的請求。參數名為 After

  • 前置路由謂詞工廠

    該謂詞匹配當前日期時間之前發生的請求。參數名為 Before

  • 時間段路由謂詞工廠

    該謂詞匹配在datetime1之後和datetime2之前發生的請求。參數名為 Between

  • cookie路由謂詞工廠

    該謂詞匹配具有給定名稱的cookie,並且值匹配正則表達式。參數名為 Cookie

  • 標頭路由謂詞工廠

    該謂詞與具有給定名稱的標頭匹配,並且值與正則表達式匹配。參數名為 Header

  • 主機路由謂詞工廠

    該謂詞是指由路由進行匹配,匹配多個路由時用,隔開。參數名為 Host

  • 方法路由謂詞工廠

    該參數是一個或多個要匹配的HTTP方法。參數名為 Method

  • 路徑路由謂詞工廠

    該謂詞是指在請求路徑上加一個前綴,以此來匹配。參數名為 Path

  • 查詢路由謂詞工廠

  • RemoteAddr路由謂詞工廠

  • 重量路線謂詞工廠

其中,我們比較常用的就是路徑路由謂詞工廠,配合StripPrefix GatewayFilter工廠,實現我們的路由匹配轉發。

路徑路由謂詞工廠配置如下:

spring:
  cloud:
    gateway:
	  discovery:
          locator:
          	enabled: true # 開啟從註冊中心動態創建路由的功能,利用微服務名稱進行路由
      routes:
          # 路由id,建議配合服務名
        - id: demo_route 
          #匹配路由名
          uri: lb://demo-provider 
          predicates:
	  # 斷言,路徑相匹配的進行路由
          - Path=/demo/** 

配置的含義就是,如果請求路徑中是/demo/**,則轉發到demo-provider服務。

網關過濾器

在spring cloud gateway 2.2.2.RELEASE版本中,已經默認實現了30種過濾器。

序號 過濾器工廠 作用 參數
1 AddRequestHeader 為原始請求添加Header Header的名稱及值
2 AddRequestParameter 為原始請求添加請求參數 參數名稱及值
3 AddResponseHeader 為原始響應添加Header Header的名稱及值
4 DedupeResponseHeader 剔除響應頭中重複的值 需要去重的Header名稱及去重策略
5 Hystrix 為路由引入Hystrix的斷路器保護 HystrixCommand的名稱
6 CircuitBreaker 為路由引入Resilience4J斷路器保護 CircuitBreaker的名稱
7 FallbackHeaders 為fallbackUri的請求頭中添加具體的異常信息 Header的名稱
MapRequestHeader 更新原始請求中的Header Header的值
9 PrefixPath 為原始請求頭添加前綴 前綴路徑
10 PreserveHostHeader 為請求添加preserverHostHeader=true的屬性,路由過濾器會檢查該屬性以決定是否要發送原始的host
11 RequestRateLimiter 用於對請求限流,限流算法為令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
12 RedirectTo 將原始請求重定向到指定的url http狀態碼及重定向的url
13 RemoveHopByHopHeadersFilter 為原始請求刪除IETF組織規定的一系列Header 默認就會啟用,可以通過配置指定僅刪除哪些Header
14 RemoveRequestHeader 為原始請求刪除某個Header Header名稱
15 RemoveResponseHeader 為原始響應刪除某個Header Header名稱
16 RewritePath 重寫原始的請求路徑 原始路徑正則表達式以及重寫後路徑的正則表達式
RewriteLocationResponseHeader 重寫響應頭的Location 的值
18 RewriteResponseHeader 重寫原始響應中的某個Header Header名稱,值的正則表達式,重寫后的值
19 SaveSession 在轉發請求之前,強制執行WebSession::save操作
20 SecureHeaders 為原始響應添加一系列起安全作用的響應頭 無,支持修改這些安全響應頭的值
21 SetPath 修改原始的請求路徑 修改后的值
22 SetRequestHeader 修改原始請求中的某個Header的值 Header名稱,修改后的值
23 SetResponseHeader 修改原始響應中某個Header的值 Header名稱,修改后的值
24 SetStatus 修改原始響應的狀態碼 HTTP 狀態碼,可以是数字,也可以是字符串
25 StripPrefix 用於截斷原始請求的路徑 使用數字錶示要截斷的路徑的數量
26 Retry 針對不同的響應進行重試 retries、statuses、methods、series
27 RequestSize 設置允許接收最大請求包的大小。如果請求包大小超過設置的值,則返回 413 Payload Too Large設置允許接收最大請求包的大小。如果請求包大小超過設置的值,則返回 413 Payload Too Large 請求包大小,單位為字節,默認值為5M
28 ModifyRequestBody 在轉發請求之前修改原始請求體內容 修改后的請求體內容
29 ModifyResponseBody 修改原始響應體的內容 修改后的響應體內容
30 Default 為所有路由添加過濾器 過濾器工廠名稱及值

這裏比較常用的如第25種,配置如下:

spring:
  cloud:
    gateway:
	  discovery:
          locator:
          	enabled: true # 開啟從註冊中心動態創建路由的功能,利用微服務名稱進行路由
      routes:
		  # 路由id,建議配合服務名
        - id: demo_route 
          #匹配路由名
          uri: lb://demo-provider 
          predicates:
		  # 斷言,路徑相匹配的進行路由
          - Path=/demo/** 
          filters:
          - StripPrefix=1

一般情況下我們配合path路由使用,這裏的意思是假如,我們的demo-provider服務種有一個/test的接口,實際上我們的請求路徑經過網關時應該時/demo/test,這樣就能把這個路由分發到demo-provider服務中,但是分發過去的路由是/demo/test,和我們實際的/test接口不一樣。這時候我們用StripPrefix=1,來截取掉一級路由,這樣轉發過去的路由就是/test了。

自定義網關過濾器

除了上面提供的30種過濾器外,我們還可以實現自定義的過濾器。

1. 實現GatewayFilter接口和Ordered接口

gatewayFilter接口是為了實現請求過濾,ordered接口是為了給過濾器設定優先級,值越大級別越低。

想要實現一個自定義的過濾器,無非就是兩個步驟:1.實現過濾器,2.將過濾器添加到具體路由上。

public class TokenGatewayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("這裏處理自身邏輯");

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

@Configuration
class RouteConfiguration{

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder){

        return builder.routes().route( r->
                r.path("/demo/**")
                .uri("lb://demo-provider ")
                .filter(new TokenGatewayFilter())
                .id("demo_route "))
                .build();
    }
}

2.繼承AbstractGatewayFilterFactory類

@Component
public class TokenCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenCheckGatewayFilterFactory.Config> {
    public TokenCheckGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
        	system.out.println("這裏處理自身邏輯")
            return chain.filter(exchange);
        };

    }

    public static class Config {
        // 控制是否開啟認證
        private boolean enabled = true;

        public Config() {}

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
}

這裏我們可以直接在application.yml中為需要過濾的路由添加這個過濾器。

spring:
  cloud:
    gateway:
      routes:
        - id: demo_route # 路由id,建議配合服務名
          uri: lb://demo-provider #匹配路由名
          predicates:
          - Path=/demo/** # 斷言,路徑相匹配的進行路由
          filters:
          - TokenCheck=true

需要注意的是,這個地方自定義的過濾器名稱必須是XXGatewayFilterFactory,並且配置文件中配置過濾器時名字必須時這個XX

當然,我們也可以為每個路由都添加這個過濾器,可以直接這樣寫配置,而不用在每個路由上都去寫。

spring:
  cloud:
    gateway:
      default-filters:
        - TokenCheck=true

3.實現GlobalFilter和ordered

這個GlobalFilter從名字中就可以看出,是一個全局過濾器,也就是說實現這個接口后,所有的請求都會被過濾,我們就不需要在去找往某個路由中加過濾器了。

@Component
public class TokenGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("這裏處理自身邏輯");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

以上就是實現自定義網關過濾器的三種方式了。實際開發中根據需求來實現合適的過濾器就可以了。

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準

加州電動車市場吹風向?純電動車超越插電式油電車

加州因為諸多有利電動車發展的政策,成為全球電動車的領先市場,其市場走向動見觀瞻,過去電動車市場曾經以插電式油電混合車為主,純電動車占較少比例,但如今加州市場率先反轉,純電動車與插電式油電混合車出現翻轉,這也代表全球電動車市場可能將開始往純電動車傾斜。

加州的總體電動車市場持續成長,2016 年純電動車加上插電式油電混合車,總市佔為 3.6%,2017 年提升到 4.8%,到 2018 年上半年,再提升到 6.2%,雖然占總體市場仍低,但市佔比例增加的幅度相當可觀。在分項部分,2014 年時,純電動車在加州市場已經追上差距,與插電式油電混合車已經達到市佔比例相當,如今純電動車更勝一籌,2018 上半年,純電動車在加州市佔 3.3%,超越插電式油電混合車的 2.9%。

不僅電動車追上插電式油電混合車,兩者的快速成長,也追上了傳統油電混合車,傳統油電混合車並不被視為電動車,在過去,傳統油電混合車的市佔遠高於電動車與插電式油電混合車,2014 年時傳統油電混合車市佔 6.3%,當年插電式油電混合車市佔僅 1.6%,純電動車也僅占 1.6%,顯示消費者對於加油還是比充電更有信心。

然而近年來趨勢有反轉的傾向,傳統油電混合車市佔節節下滑,2015 年落到 5.8%,2016 年再跌到 4.7%,2017 年 4.6%,2018 年上半年則約為 4%;相對的,插電式油電混合車與電動車則蒸蒸日上,2015 年兩者分別為 1.4%、1.7%,2016 年 1.7%、1.9%,2017 年 2.2%、2.6%,到 2018 年上半年的 2.9%、3.3%。

總體來說,可說插電式油電混合車取代了傳統油電混合車,在此同時,純電動車則成長還超前插電式油電混合車。過去車廠對於電動車的演變看法不同,有車廠認為會先經歷傳統油電混合車成為主流的年代,之後再過渡到插電式油電混合車為主流,最後才進入純電動車時代,但加州經驗看來,3 種車都還未成為主流,傳統油電混合車就已經節節下滑,將下台一鞠躬,插電式油電混合車雖然崛起,但純電動車更勝一籌,由此觀之,或許未來的車市發展,還是會直接跳到純電動車,而沒有所謂油電混合車時代。

(合作媒體:。首圖來源:)

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

【其他文章推薦】

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

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

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

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

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

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

美環保組織:燕麥片含致癌除草劑 美國桂格、家樂氏上榜

摘錄自2018年08月18日蘋果日報美國報導

美國環保組織「環境工作小組」(Environmental Working Group,EWG)近日選取45種燕麥食物送化驗,結果發現其中43種含有除草劑「年年春」(Roundup)的主要化學物質嘉磷塞(glyphosate),且超過2/3產品的嘉磷塞含量,超出兒童攝取的安全份量。而讓人驚訝的是,美國的桂格燕麥(Quaker Oats)、家樂氏(Kellogg’s)和Cheerios等的化學物含量最高。對此,美國桂格燕麥及家樂氏均強調,旗下食品合乎安全標準。

EWG指,兒童對嘉磷塞的安全攝取量,不應超過160 ppb,但桂格燕麥兩個樣本,均被驗出嘉磷塞的濃度超過1000 ppb。此外,桂格的另外兩種產品「恐龍蛋即食燕麥片」(Quaker’s dinosaur eggs instant oatmeal)和「鋼切燕麥粒」(Steel Cut Oats),嘉磷塞含量也高達500 ppb。

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

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

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

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

122隻珍稀海龜陳屍墨西哥海灘 當局調查中

摘錄自2018年8月19日蘋果日報墨西哥報導

墨西哥南部恰帕斯州(Chiapas)一處野生動物保護區,近日有多達122隻珍稀海龜死亡,當局正積極調查。

《墨西哥每日新聞》(Mexico News Daily)報導,不幸的是,這些海龜屍體的腐敗狀況使調查進度不樂觀,不易執行驗屍或任何切片檢驗。這些海龜大多是麗龜(olive ridley species),成年後身長可達1公尺,平均壽命約100歲。

當地保護區管理委員會負責人巴羅拉(Adrián Méndez Barrera)指出,7月24日起,這些海龜屍體開始逐漸出現。為避免麗龜數量持續減少,聯邦政府、州政府與當地補漁業者目前著手監控周邊區域,以避免再有麗龜被捕,或有人取走牠們的蛋。

同時,當局也將檢驗當地海水樣本,看看是否含有有害物質,避免再有珍貴的動物受害。

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準

特斯拉上海子公司台幣 44 億元取得上海土地,超級工廠正式落地

根據中國《文匯報》的報導,電動車大廠特斯拉(TESLA)上海子公司在 10 月 17 日下午,成功取得上海臨港裝備產業區總面積達到 864,885 平方公尺的 Q01-05 地塊工業用地,並與上海市規劃和國土資源管理局正式簽訂土地出讓契約,使得特斯拉中國超級工廠(Gigafactory 3)正式在上海落地。

報導指出,根據上海土地市場官網表示,特斯拉上海子公司是以 9.73 億人民幣 (約新台幣 44 億元) 的價格,取得上海臨港裝備產業區 864,885 平方公尺工業用地,象徵著特斯拉中國上海超級工廠將在當地正式落地。

另外,根據《彭博社》的報導,特斯拉已經就中國上海臨港工廠的土地與上海市規劃和國土資源管理局簽訂出讓協議。未來將加快在當地的工廠建設,在這 86 萬平方公尺的土地設立中國超級工廠。根據之前所傳出的消息,特斯拉預計在該超級工廠建立完成後,在此生產每年最高 50 萬輛電動車,以供應全世界市場的需求,只是要達到最高每年 50 萬輛電動車的產能,還要等工廠建立完成至少兩年後才能達成。

值得一提的是,從 7 月 10 日特斯拉與上海臨港管委會、臨港集團簽署純電動車計畫投資協議,到 10 月 17 日土地正式取得,特斯拉只花了約 3 個月的時間。也就是 2018 年 7 月份,特斯拉正式確認將在此臨港地區獨資建設集研發、製造、銷售等功能於一體的特斯拉超級工廠(Gigafactory 3)。而這一預計總金額將可能達到 20 億美元,是上海有史以來最大的外資製造業投資計畫。

另外,根據特斯拉所公布的資料,作為特斯拉旗下目前售價最低和關注度最高的車型,Model 3 的產量和交付量在 2018 年都有明顯增加,前 3 季的產量和交付量均超過了 5 萬輛,使得該款電動汽車的產量和交付量中在所有產品中的比重超過了 60%。

而就在 Model 3 產量提升的同時,特斯拉也沒有忽視更早推出的 Model S 和 Model X 車款。從其公佈的資料來看,這兩款電動汽車在 2018 年前 3 季已交付 71,760 輛,使得這兩款型在 2018 年全年 10 萬輛的交付量目標將有望達成。

(合作媒體:。首圖來源:)

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

【其他文章推薦】

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

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

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

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

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

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

具備效率高壽命長優勢,超級電容可在油電混合車大放異彩

目前全電動車充電少說需要 20-30 分鐘,顯然是個不短的時間,若沒電總不能一直停在路邊充電。因此在大規模採用全電動車之前,油電混合車還是電動車市場的主流,在傳統汽車中新添蓄電池及電動機兩種動力來源,而隨著技術的更迭,現在也有研究員認為若以超級電容取代現有電池,或許可進一步加速混合動力與電動車的發展。

油電混合車可說是傳統燃油車邁向全電動車的重要進展,擁有傳統燃油內燃機與電池電動馬達兩種驅動系統,電池可直接推動車輛,同時回收剩餘的動能為電池充電;傳統內燃機能則可直接產生機械動力推動車輛,或是當成發電機推動電動機或為電池充電。在長距離下就不用補充燃油,能以電動車模式行駛,油耗量與碳排放量不僅都比傳統的汽車還要少,也有助於城市達成節能減碳目標。

其中電池儲能技術在電動車與油電混合車中居關鍵地位,對此美國奧克拉荷馬基督大學 研究員 Surya Sita krishnam raju Alluru 提出一項解決方案,認為技術與發展日益成熟的超級電容可為電動車帶來新的未來。

超級電容具有高效儲能特性,是介於傳統電容與電池之間的雙電層電容,與鋰電池相比不需將電能轉成化學能,可直接以物理方式儲存電能,具有高功率密度、壽命長、充放電效率高、高電壓、耐高溫等優點,有望為提供車輛瞬間功率輸出與提升性能。

該研究員認為超級電容的快充為主要優勢,不管是與電池結合還是獨立使用都對車輛大有裨益,不僅能為電池供電、也可以和內燃機一起提供驅動力,將可提高油電混合車的功率控制與效率,行駛距離也可以進一步提升,且超級電容除了能結合電容與電池提升電路穩定性,也可以調節油電混合車的耗油量。

通常電動車與油電混合車都有搭載動能回收系統(KERS),可將煞車時的動能回收轉為電能,當能量累積到一定程度後駕駛就能利用電力加速推動引擎轉速,藉此獲得更大的動力,而超級電容可更有效的儲存電能。

過去研究也指出,由於超級電容可提供車輛瞬間高功率控制需求,進而提高電池儲能系統的緩衝保護,避免電池過度放電。目前也有不少油電混合車已使用超級電容來取代電池,不僅充電快速,還能可以回收更多煞車能量,並解決電池壽命問題,只不過超級電容目前能量密度仍不高,儲存容量還是比較低,在大規模採用之前,還得進一步證明其性能與優勢。

(首圖來源: CC BY-SA 2.0。文/DaisyChuang)

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

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

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

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

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

合攻電動巴士商機,車王電集團攜日住友商事集團簽 MOU

為響應政府 2030 年公車全面電動化政策,由車王電、華德動能與日本住友商事、台灣住友商社於 29 日共同簽署「電動商用車暨汰役電池應用開發合作備忘錄(MOU)」,將透過台日產業合作,將台灣電動車及智慧儲能產業推向國內外市場。

車王電指出,電動巴士將是未來智慧城市非常重要的一環,據彭博新能源財經的報導,預計全球電動巴士到 2025 年將超過百萬輛,相當於全球城市公共巴士車隊的 47%。

車王電表示,集團旗下華德動能為國內唯一獲交通部核發「自主開發設計」資格的電動車企業,最新發表的新型電動巴士具超長行駛續航力,且電池使用壽命長、車輛性能超越國際水準,具極優成本效益比,而日本住友商事是日本屈指可數的企業集團,為在全球開展業務的綜合性跨國企業,藉由此次合作計劃,以期共同攜手將電動商用車推向國際市場。

車王電亦表示,將電動車用的電池作二次應用,透過電池管理平衡技術提升並延長電池使用年限及效率,再應用於儲能系統上,為推進循環經濟的重要實踐;此外,公司近年來致力於儲能事業的佈局與發展,建置主動式電池平衡技術,達成大幅延長汰役電池之壽命與效率。

車王電進一步表示,華德動能結合公司建置完成國內首座創能、儲能、用能(三能)之智慧微電網系統於欣欣客運電動大巴木柵充電場站,此充電場站整合市電、太陽能、鋰電儲能櫃及電動車充電機,並藉雲端智能行控中心充份掌握及控制行車資訊、太陽能發電量、儲能狀態及耗能資訊,將成為國內首座大型智慧節能電動車充電場站示範場域。

在台北市政府主導規劃下,欣欣客運係於 106 年 12 月取得北市第一條電動公車路線「動物園 – 信義快 – 松山車站」的路權,而經過近 5 個月的籌備及公開招標,由華德動能於 107 年 5 月取得承製此批車輛之標案;此一路線於 29 日正式通車。

(本文內容由 授權使用。首圖來源:)

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準