標籤: 台北網頁設計公司推薦

  • 這是下一個 Tesla!新創公司 Faraday 宣布 10 億美元電動車投資計畫

    這是下一個 Tesla!新創公司 Faraday 宣布 10 億美元電動車投資計畫

    近日一家在洛杉磯成立的新創公司 Faraday Future 引發了巨大關注,號稱投資 10 億美元建設電動車製造廠,據該公司官網顯示 4 位副總裁來自 Tesla,團隊規模大約為 400 人,這一投資規模在整個電動車產業來看,都不是一筆小數目。

    Faraday Future 的總部位於洛杉磯南部,相比於一般新創公司而言,Faraday Future 的團隊規模比較大,目前已經擁有了 400 名員工,這家專注於電動車市場的新創公司並沒有在業內引發太多關注。最近華爾街日報報導該公司宣布投資 10 億美元建廠,這一筆投資使得 Faraday 聲名大振。   據該公司的網站資訊顯示,Faraday Future 將以使用者為中心,把一流的技術引入電動車設計、致力於連結使用者的駕駛體驗和生活。4 位副總裁均來自電動車製造商 Tesla,Tesla Model S 製造業務總監 Dag Reckhorn 擔任製造業務副總裁,Tesla 前人力資源總監 Alan Cherry 擔任 Faraday 的人力資源副總裁,Tesla 前採購總監 Tom Wessner 擔任 Faraday 供應鏈管理副總裁。但未公開 CEO 的資訊,據加州政府提供的 Faraday Future 註冊資訊顯示,該公司的 CEO 與中國網路公司樂視有密切關係,出任 CEO 的正是樂視 CEO 的助理,樂視在 2015 年上半年發表了超級汽車計畫。  

      Faraday 研發副總裁、Tesla 前總監 Nick Sampson 表示,市面上的汽車已經不能滿足用戶的需求,Faraday 將提供最智慧化的電動車,幫助用戶與外部世界連接,這位高階主管拒絕公開 Faraday 的投資方。Nick Sampson 於 2012 年 1 月從 Tesla 離職,對於他的離職,Tesla CEO Elon Musk 曾公開表示是他勸 Nick Sampson 離職的,因為 Tesla 沒有適合他的職位。   從團隊構成到產品戰略,這家神秘新創公司直指 Tesla,在公司的名稱上也與 Tesla 有異曲同工之妙,Tesla 的名字來自於交流電發明者 Nikola Tesla,而 Faraday 的名字則是來自電磁感應的發現者 Michael Faraday。

    (本文授權轉載自《》─〈〉)

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • .NET進階篇06-async異步、thread多線程2

    .NET進階篇06-async異步、thread多線程2

    知識需要不斷積累、總結和沉澱,思考和寫作是成長的催化劑

    內容目錄

    一、線程Thread

    .NET中線程操作封裝為了Thread類,可以讓開發者對線程進行直觀操作。Thread提供了實例方法用於管理線程的生命周期和靜態方法用於控制線程的一些訪問存儲等一些外在的屬性,相當於工作空間環境變量了

    1、生命周期

    線程的生命周期有創建、啟動、可能掛起、等待、恢復、異常、然後結束。用Thread類可以容易控制一個線程的全生命周期

    Thread類的構造函數重載可以接受ThreadStart無參數和ParameterizedThreadStart有參數的委託,然後調用實例的Start()方法啟動線程。Thread的構造函數的帶有參數的委託,參數是一個object類型,因為我們可以傳入任何信息

    Thread t1 = new Thread(() => {
        Console.WriteLine($"新線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    });
    t1.Start();
    Thread t2 = new Thread((obj) => {
        Console.WriteLine($"新線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")},參數 {obj.ToString()}");
    });
    t2.Start("hello kitty");

    線程啟動后,可以調用線程的Suspend()掛起線程,線程就會處於休眠狀態(不繼續執行線程內代碼),調用Resume()喚醒線程,還有一個不太建議使用的Abort()通過拋出異常的方式來銷毀線程,隨後線程的狀態就會變為AbortRequested

    常用的還有線程的等待,在主線程上啟用工作線程后,有時需要等待工作線程的完成后,主線程才繼續工作。可以調用實例方法Join(),當然我們可以傳入時間參數來表明我主線程最多等你多久

    2、後台線程

    上一章我們知道Thread默認創建的是前台線程,前台線程會阻止系統進程的退出,就是啟動之後一定要完成任務的後台線程會伴隨着進程的退出而退出。通過設置屬性IsBackground=true改為後台線程。另外還可以通過設置Priority指定線程的優先級。但這個並不總會如你所想設置了高優先級就一定最先執行。操作系統會優化調度,這也是線程不太好控制的原因之一

    3、靜態方法

    上面介紹的都是Tread的實例方法,Thread還有一些常用靜態方法。有時線程設置不當,會有些意想不到的的bug

    1.線程本地存儲

    AllocateDataSlot和AllocateNamedDataSlot用於給所有線程分配一個數據槽。像下面例子所示,如果不在子線程中給數據槽中放入數據,是獲取不到其他線程往裡面放的數據。

    var slot= Thread.AllocateNamedDataSlot("testSlot");
    //Thread.FreeNamedDataSlot("testSlot");
    Thread.SetData(slot, "hello kitty");
    Thread t1 = new Thread(() => {
        //Thread.SetData(slot, "hello kitty");
        var obj = Thread.GetData(slot);
        Console.WriteLine($"子線程:{obj}");//obj沒有值
    });
    t1.Start();

    var obj2 = Thread.GetData(slot);
    Console.WriteLine($"主線程:{obj2}");

    在聲明數據槽的時候.NET提醒我們如果要更好的性能,請使用ThreadStaticAttribute標記字段。什麼意思?我們來看下面這個例子

    //
    // 摘要:
    //     在所有線程上分配未命名的數據槽。 為了獲得更好的性能,請改用以 System.ThreadStaticAttribute 特性標記的字段。
    //
    // 返回結果:
    //     所有線程上已分配的命名數據槽。
    public static LocalDataStoreSlot AllocateDataSlot();

    例子中的如果不在靜態字段上標記ThreadStatic輸出結果就會一致。ThreadStatic標記指示各線程的靜態字段值是否唯一

    [ThreadStatic]
    static string name = string.Empty;
    public void Function()
    {
        name = "kitty";
        Thread t1 = new Thread(() => {
            Console.WriteLine($"子線程:{name}");//輸出空
        });
        t1.Start();
        Console.WriteLine($"主線程:{name}");//輸出kitty
    }

    還有一個ThreadLocal提供線程數據的本地存儲,用法和上面一樣,在每個線程中聲明數據僅供自己使用

    ThreadLocal<string> local = new ThreadLocal<string>() { };
    local.Value = "hello kitty";
    Thread t = new Thread(() => {
        Console.WriteLine($"子線程:{local.Value}");
    });
    t.Start();
    Console.WriteLine($"主線程:{local.Value}");

    上面的靜態方法用於線程的本地存儲TLS(Thread Local Storage),Thread.Sleep方法在開發調試時也是經常用的,讓線程掛起指定的時間來模擬耗時操作

    2.內存柵欄

    先說一個常識問題,為什麼我們發布版本時候要用Release發布?Release更小更快,做了很多優化,但優化對我們是透明的(計算機里透明認為是個黑盒子,內部邏輯細節對我們不開放,和生活中透明意味着完全掌握了解不欺瞞剛好相反),一般優化不會影響程序的運行,我們先借用網上的一個例子

    bool isStop = false;
    Thread t = new Thread(() => {
        bool isSuccess = false;
        while (!isStop)
        {
            isSuccess = !isStop;
        }
    });
    t.Start();
    Thread.Sleep(1000);
    isStop = true;
    t.Join();
    Console.WriteLine("主線程執行結束");

    上面例子如果在debug下能正確執行完直到輸出“主程序執行結束”,然而在release下卻一直會等待子線程的完成。這裏子線程中isStop一直為false。首先這是一個由多線程共享變量引起的問題,所以我們建議最好的解決辦法就是盡量不共享變量,其次可以使用Thread.MemoryBarrier和VolatileRead/Write以及其他鎖機制犧牲一點性能來換取數據的安全。(上面例子測試如果在子線程while中進行Console.writeLine操作,奇怪的發現release下也能正常輸出了,猜測應該是進行了內存數據的更新)

    release優化會將t線程中的isStop變量的值加載到CPU Cache中,而主線程修改了isStop值在內存中,所以子線程拿不到更新后的值,造成數據不一致。那麼解決辦法就是取值時從內存中獲取。Thread.MemoryBarrier()就可以讓在此方法之前的內存寫入都及時的從CPU Cache中更新到內存中,在此之後的內存讀取都要從內存中獲取,而不是CPU Cache。在例子中的while內增加Thread.MemoryBarrier()就能避免數據不一致問題。VolatileRead/Write是對MemoryBarrier的分開解釋,從處理器讀取,從處理器寫入。

    4、返回值

    前面聲明線程時,可以傳遞參數,那麼想要有返回值該如何去做呢?Thread並沒有提供返回值的操作,後面.NET給出的對Thead的高級封裝給出了解決方案,直接使用即可。那目前我們使用thread類就要自己實現下帶有返回值的線程操作,都是通過委託實現的,這裏簡單介紹一種,(共享外部變量也是可以,不建議)

    private Func<T> ThreadWithReturn<T>(Func<T> func)
    {
        T t = default(T);
        Thread thread = new Thread(() =>
        {
            t = func.Invoke();
        });
        thread.Start();
        return () =>

        {
            thread.Join();
            return t;
        };
    }
    //調用
    Func<intfunc = this.ThreadWithReturn<int>(() =>
    {
        Thread.Sleep(2000);
        return DateTime.Now.Millisecond;
    });
    int iResult = func.Invoke();

    二、線程池ThreadPool

    .NET起初提供Thread線程類,功能很豐富,API也很多,所以使用起來比較困難,況且線程還不都是很像理想中運行,所以從2.0開始提供了ThreadPool線程池靜態類,全是靜態方法,隱藏了諸多Thread的接口,讓線程使用起來更輕鬆。線程池可用於執行任務、發送工作項、處理異步 I/O、代表其他線程等待以及處理計時器

    1、工作隊列

    常用ThreadPool線程池靜態方法QueueUserWorkItem用於將方法排入線程池隊列中執行,如果線程池中有閑置線程就會執行,QueueUserWorkItem方法的參數可以指定一個回調函數委託並且傳入參數,像下面這樣

    ThreadPool.QueueUserWorkItem((obj) => {
                    Console.WriteLine($"線程池中線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,傳入 {obj.ToString()}");
                },"hello kitty");

    2、工作線程和IO線程

    一般異步任務的執行,不涉及到網絡文件等IO操作的,計算密集型,開發者來調用。而IO線程一般用在文件網絡上,是CLR調用的,開發者無需管。工作線程發起文件訪問調用,由驅動器完成后通知IO線程,IO線程則執行異步任務的回調函數

    獲取和設置最小最大的工作線程和IO線程

    ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
    ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
    ThreadPool.SetMaxThreads(1616);
    ThreadPool.SetMinThreads(88);

    3、和Thread區別

    如果計算機只有8個核,同時可以有8個任務運行。現在我們有10個任務需要運行,用Thread就需要創建10個線程,用ThreadPool可能只需要利用8個線程就行,節約了空間和時間。線程池中的線程默認先啟動最小線程數量的線程,然後根據需要增減數量。線程池使用起來簡單,但也有一些限制,線程池中的線程都是後台線程,不能設置優先級,常用於耗時較短的任務。線程池中線程也可以阻塞等待,利用ManualResetEvent去通知,但一般不會使用。

    4、定時器

    .NET中有很多可以實現定時器的功能,在ThreadPool中,我們可以利用RegisterWaitForSingleObject來註冊一個指定時間的委託等待。像下面這樣,將每隔一秒就輸出消息

    ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(true), new WaitOrTimerCallback((obj, b) =>
    {
        Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
    }),"hello kitty",1000,false);

    我們平常見過比較多的還是timer類,timer類在.net內是好幾個地方都有的,在System.Threading、
    System.Timer、System.Windows.Form、System.Web.UI等裏面都有Timer,後面都是在第一個System.Threading里的Timer擴展

    System.Threading.Timer timer = new System.Threading.Timer((obj) =>
    {
        Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
    },"hello kitty",1000,1000);

    timer的底層有一個TimerQueue,利用ThreadPool.UnsafeQueueUserWorkItem來完成定時功能,和上面我們使用的ThreadPool定時器有一點區別

    實際開發中,簡單定時timer就夠用,但一般業務場景比較複雜,需要定製個性化的定時器,比如每月幾號執行,每月第幾個星期幾,幾點執行,工作日執行等。因此我們使用Quarz.NET定時框架,後面框架整合時會用到,用起來也是很簡單的

    先就啰嗦這兩點吧,下一篇應該是Task、Parallel以及Async/Await,然後總結介紹下C#的線程模式、線程同步鎖機制、異常處理,線程取消,線程安全集合和常見的線程問題

    天長水闊,見字如面,隨緣更新,拜了個拜~

    可關注主頁公號獲取更多哈

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • 玩轉VSCode-完整構建VSCode開發調試環境

    玩轉VSCode-完整構建VSCode開發調試環境

    隨着VSCode的不斷完善和強大,是時候將部分開發遷移到VS Code中了。

    目前使用VS2019開發.NET Core應用,一直有一個想法,在VS Code中復刻VS的開發環境,同時遷移到VS Code。

    那麼現在就開始吧。

    首先,安裝最新版的VS Code:,安裝完成后可能會提示升級,升級即可,升級后的版本信息:

    版本: 1.40.1 (system setup)
    提交: 8795a9889db74563ddd43eb0a897a2384129a619
    日期: 2019-11-13T16:49:35.976Z
    Electron: 6.1.2
    Chrome: 76.0.3809.146
    Node.js: 12.4.0
    V8: 7.6.303.31-electron.0
    OS: Windows_NT x64 10.0.16299

    接下來的操作分為幾個步驟:

    1. 安裝各種強大VS Code插件

    2. 創建.NET Core解決方案和工程

    3. 調試運行

    好的,那我們開始吧。

    一、安裝各種強大的VS Code插件

    1. C# extension for Visual Studio Code

    這個插件最重要的功能:

    • Lightweight development tools for .
    • Great C# editing support, including Syntax Highlighting, IntelliSense, Go to Definition, Find All References, etc.
    • Debugging support for .NET Core (CoreCLR). NOTE: Mono debugging is not supported. Desktop CLR debugging has .
    • Support for project.json and csproj projects on Windows, macOS and Linux.

    2. C# Extensions

    這個插件最有用的功能是可以右鍵新建C#類和C#接口,同時支持各種code snippets,例如 ctor 、prop等,具體功能特性,可以查看插件的說明。

     3. Auto-Using for C#

    這個插件自動添加using引用。

    4. vscode-solution-explorer

    這個插件給VS Code增加了解決方案tab, 支持新建解決方案、新建工程、添加引用、Nuget包,這個插件非常有用

    Adds a Solution Explorer panel where you can find a Visual Studio Solution File Explorer.

    • Can load any .sln version

    • Supports csproj, vcxproj, fsproj and vbproj (from vs2017 and before)

    • Supports dotnet core projects

    • You can create, delete, rename or move project folders and files.

    • You can create, delete, rename or move solution, solution folders and projects.

    • You can add or remove packages and references when the project is of kind CPS (dotnet core).

     

    5. Code Runner(韓俊老師出品,必屬精品)

    Run code snippet or code file for multiple languages: C, C++, Java, JavaScript, PHP, Python, Perl, Perl 6, Ruby, Go, Lua, Groovy, PowerShell, BAT/CMD, BASH/SH, F# Script, F# (.NET Core), C# Script, C# (.NET Core), VBScript, TypeScript, CoffeeScript, Scala, Swift, Julia, Crystal, OCaml Script, R, AppleScript, Elixir, Visual Basic .NET, Clojure, Haxe, Objective-C, Rust, Racket, Scheme, AutoHotkey, AutoIt, Kotlin, Dart, Free Pascal, Haskell, Nim, D, Lisp, Kit, and custom command

    即選中一段代碼,直接run

    6. vscode-icons

    通過這個插件,給各個文件和文件夾一個你更熟悉的圖標

    7. Visual Studio IntelliCode

    VS代碼智能提示,根據上下文語境,自動推薦你下一步用到的代碼,後台基於AI的

    8. NuGet Package Manager

    Nuget包管理,快速查詢定位Nuget包,並安裝。不過嘗試了一下午自定義Nuget源,沒搞定,估計是URL不對

    9. Docker

    10. Kubernetes

    其他的還需要配置GitHub、TFS類似的源代碼管理,TFS搞了兩個插件,都不好使,後續搞定后再更新一次。

     

    二、創建.NET Core解決方案和工程

    此時,VS Code的環境基本配置差不多了,接下來有兩種模式,創建解決方案和工程。

    1. 通過vscode-solution-explorer

    解決方案有了,很熟悉的感覺。

    我們可以繼續創建工程:右鍵sln,Add new project:

    此時會彈出工程模板,此時我們選擇ASP.NET Core Web API工程

    選擇C#

    然後繼續輸入工程名稱:例如 TestWebApi

    熟悉的感覺來了。此時就可以開始coding了。

    以上是我們通過vscode-solution-explorer新建解決方案和工程。同時我們可以通過命令行來搞定。

    2. 通過Dotnet CLI命令行

    新建sln:

    dotnet "new" "sln" "-n" "EricTest" "-o" "e:\Work\ServiceDependency"

    新建ASP.NET Core WebAPI工程

    dotnet "new" "webapi" "-lang" "C#" "-n" "TestWebApi" "-o" "TestWebApi"

    將TestWebApi工程添加到解決方案EricTest

    dotnet "sln" "e:\Work\ServiceDependency\EricTest.sln" "add" "e:\Work\ServiceDependency\TestWebApi\TestWebApi.csproj"

    三、調試運行

    在Debug選項卡中新增調試配置,重點設置要調試的program

    保存后,啟動調試:

     

    程序中增加斷點,然後

    輸入URL:https://localhost:5001/WeatherForecast

     既可以調試了。

     

    以上是今天集中配置VS Code開發調試環境的總結,分享給大家。

     

    周國慶

    2019//11/16

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • 快速搭建Jenkins集群

    快速搭建Jenkins集群

    關於Jenkins集群

    在Jenkins上同時執行多個任務時,單機性能可能達到瓶頸,使用Jenkins集群可以有效的解決此問題,讓多台機器同時處理這些任務可以將壓力分散,對單機版Jenkins的單點故障的隱患也有分散作用,今天就來實戰快速搭建Jenkins集群,Jenkins版本是2.190.2;

    如何做到快速搭建集群

    通過Docker可以省去大部分準備工作,您只需在Linux電腦上安裝docker,在輔以少量命令和操作即可完成集群搭建;

    環境信息

    本次實戰的環境一共要用三台電腦,它們的設置都是一樣的,如下:

    1. 操作系統:CentOS Linux release 7.6.1810
    2. 防火牆關閉
    3. docker:1.13.1

    三台電腦的信息如下:
    | 主機名 | IP地址 | 作用 |
    |–|–|–|
    | master | 192.168.133.131 | Jenkins集群的master節點,提供web服務 |
    | agent1 | 192.168.133.132 | Jenkins集群的一號工作接節點,標籤是maven |
    | agent2 | 192.168.133.133 | Jenkins集群的二號工作接節點,標籤是gradle |

    建議agent2節點的內存大於4G,因為下一篇的實戰操作會用agent2編譯構建spring-framework,對內存的需求略大;

    準備工作

    1. 後面的所有操作都是root賬號;
    2. 在每台電腦上創建文件夾/usr/local/jenkins

      創建Jenkins的master

    3. 登錄master機器,執行以下命令:
    docker run \
      -u root \
      -idt \
      --name master \
      -p 8080:8080 \
      -p 50000:50000 \
      -v /usr/local/jenkins:/var/jenkins_home \
      -v /var/run/docker.sock:/var/run/docker.sock \
      jenkinsci/blueocean:1.19.0
    1. 執行docker logs master,會在控制台显示jenkins的登錄秘鑰,如下圖紅框所示:
    2. 瀏覽器輸入地址: ,显示Jenkins登錄頁面,如下圖所示,在紅框位置輸入剛才複製的登錄秘鑰即可登錄:
    3. 選擇安裝推薦的插件
    4. 靜候插件在線安裝完成:
    5. 接下來是創建管理員和使用實例url的操作,這裏就不多說了,您按實際情況自行斟酌;

      至此,Jenkins的master已經搭建好,接下來將agent1和agent2作為工作節點加入集群;

      加入agent1

    6. 在Jenkins網頁上新增節點,操作如下圖,先進入節點管理頁面:
    7. 如下圖,新增一個節點,名為agent1
    8. 接下來的節點詳情信息如下圖,注意四個紅框中的內容要和圖中保持一致:
    9. 保存成功後會显示機器列表,如下圖,圖標上的紅叉表示機器不在線(此時agent1還沒有接入),點擊紅框:
    10. 如下圖所示,紅框中的命令就是agent1的啟動命令,執行該命令的機器會以agent1的身份加入集群:
    11. 注意上圖紅框中的agent.jar是個名為agent.jar的文件的下載鏈接,將此文件下載到agent1電腦的/usr/local/jenkins目錄下;
    12. ssh登錄agent1電腦,執行以下命令,即可將agent1加入Jenkins集群:
    docker run \
      -u root \
      -idt \
      --name agent \
      -v /usr/local/jenkins:/usr/local/jenkins \
      bolingcavalry/openjdk-with-sshpass:8u232 \
      java -jar /usr/local/jenkins/agent.jar \
      -jnlpUrl http://192.168.133.131:8080/computer/agent1/slave-agent.jnlp \
      -secret 44c3e8d1531754b8655b53294bbde6dd99b3aaa91a250092d0d3425534ae1058 \
      -workDir "/usr/local/jenkins"

    上述命令中的後半部分,即java -jar ……就是前面圖片紅框中的agent1啟動命令,唯一要改變的是將agent.jar改成絕對路徑/usr/local/jenkins/agent.jar

    1. 上述命令的鏡像是bolingcavalry/openjdk-with-sshpass:8u232,其Dockerfile內容如下,可見非常簡單,就是OpenJDK鏡像裏面安裝了sshpass,這樣的容器可以在執行ssh命令時帶上遠程機器的密碼,而不用等待用戶輸入密碼,這樣便於shell腳本執行ssh命令:
    FROM openjdk:8u232
    
    ARG DEBIAN_FRONTEND=noninteractive
    RUN apt-get update && apt-get install --assume-yes sshpass
    1. 去Jenkins的網頁上查看節點列表,如下圖,可見agent1已經成功加入:

      加入agent2

      agent2加入集群的方式和agent1大部分是一樣的,只有以下兩點要注意:

    2. 在Jenkins頁面上創建節點,名稱是agent2
    3. agent2的標籤是gradle,如下圖紅框所示:
    4. 此時agent2也加入成功:

      至此,Jenkins集群搭建完成,這兩個節點帶有不同的標籤,下一篇文章中,我們在這個集群環境創建pipeline任務,並通過標籤被分配到不同的節點上,實現多節點并行執行;

      歡迎關注公眾號:程序員欣宸

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • 微信作弊,為3款小遊戲引擎開掛增速,將給小遊戲帶來怎樣的利好?

    微信作弊,為3款小遊戲引擎開掛增速,將給小遊戲帶來怎樣的利好?

    11月14日小遊戲開發圈子,有一條重磅新聞:“微信小遊戲聯合遊戲引擎廠商,推出引擎插件功能,可為小遊戲提升0.5~2秒的啟動時間”。

    引擎插件是個什麼東西?

    昨天有不少人在問曉衡:“引擎插件到底是個什麼東西?”、“又要讓我學習新東西嗎?”、“引擎插件是怎麼加速的,不太明白?” …

    曉衡也在第一時間,將文檔通讀了一遍,並用自己的小遊戲工程做了測試,對微信小遊戲引擎插件算是有了一個簡單的認識,看下圖:

    普通模式,每一個使用遊戲引擎開發的小遊戲,都需要下載遊戲引擎代碼模塊。

    引擎插件模式,僅第一個遊戲需要下載引擎代碼,其它使用同類引擎的遊戲,可共享之前 A 遊戲下載過的遊戲引擎代碼,從而加速遊戲的啟動時間。

    從事小遊戲開發和運營的夥伴應該都很了解,H5、小遊戲注重啟動加載速度,它對新用戶的體驗和流失都至關重要。

    啟動概況分析

    估計有人會覺得引擎插件就加快了0.5~2秒有什麼用?眨個眼的時間而已。

    其實對使用 Cocos Creator 開發的休閑類的小遊戲來說,目前的微信小遊戲啟動速度已經很不錯了,首包含引擎的話,iOS 在4 ~ 6秒啟動,Android 大多可以在6~8秒左右打開首屏,並不像微信吹噓的1秒啟動,估計只有 引擎和資源全放子包的遊戲可以做到!

    下面我將自己個人開發的一款微信小遊戲,在微信公測的前後两天做了一個數據統計,想窺視一下啟動性能對留存的影響,下圖是曉衡的遊戲在8月7日 ~ 8月9日時的活躍情況:

    遊戲是在8月7日的晚上10:00點打開的微信公測,微信平台在24小時內持續導入5184的用戶,當天遊戲啟動8121次。不過圖片上的數據比較尷尬,公測一過就沒幾個玩家了,但它不是我們要講的重點,我們是用這個時間節點、用戶數量,來看微信小遊戲的啟動性能表現。

    iOS啟動概況

    Android啟動概況

    從圖中看,8月7日這天 iOS 的總啟動時間比 Android 快 3.88 秒,Android 的用戶流失比 iOS 要多 12.55%,這裏重點也不是說 iOS 和 Android 系統那個好,而是看遊戲的啟動時間對首屏打開留存的影響。

    這是另一個朋友的遊戲《周車勞盾》在9月14日微信公測4800+用戶,遊戲啟動7000+次,下面是它在9月13~9月15日的啟動概況:

    《周車勞盾》的 iOS 首屏打開留存率由於用戶數太少,不太好與 Android 對比,並且朋友說當時遊戲沒有做分包優化。在9月14日公測當天,由於新用戶多,iOS、Android 的啟動速度都不快,在 10 秒左右。從中也可以看出微信小遊戲用戶,以及微信導量用戶,以 Android 屬性為主。

    啟動流失分析

    下圖是曉衡的遊戲在8月8日公測時的 Android 手機用戶流失分佈情況,統計一共有 893 名流失用戶:

    從前面的啟動概況看到,小遊戲啟動進入首屏是在8.38s,我們以9秒為分界線,將上圖分成左右兩部分:

    • 右邊標註綠色線框,是已經進入遊戲后流失的人數,這部分的優化需要美術和策劃同學的幫助。
    • 左邊紅色線框中的用戶,是在遊戲啟動過程中流失掉的共計679人佔76%,而且前4秒流失的最多共543占 60%,如果不計算已經打開首屏的更是高達80%,因此前幾秒它才是我們關心的重點。

    曉衡根據平常使用微信的習慣,模擬分析一下前8秒的用戶是大概會是什麼情況走失的,需要注意的一個前題是,這些用戶都是微信導量進入的,絕大多是手滑不小心點到廣告,並不是目標用戶。

    • 第1秒:1秒流失用戶,手滑的機率最大,似乎經過專業訓練,眼、腦、手的速度都非常的快,遊戲是什麼都沒看清就閃人了;
    • 第2秒:2秒流失用戶,與1秒戶大概差不多,只是動作稍慢而已,此時遊戲圖標已經進入視覺系統,但估計比較模糊,瞬間閃人;
    • 第3秒:3秒流失用戶,不僅遊戲圖標已經從視覺系統進入大腦,遊戲名字估計也是能看清楚,但是沒有任何感覺,同樣是條件反射,快速點擊關閉;
    • 第4秒:4秒流失用戶,已經是把遊戲圖標、名字已經完全進入大腦神經迴路,給他反饋的信號是沒有愛,甚至是反感,迅速閃人了。第4秒很關鍵,因為用戶已經有了思考!
    • 第5~6秒:5~6秒流失用戶,認真看完遊戲圖標、名字,以及加載進度,經過大腦綜合反饋,這個遊戲不值得等待,88了!
    • 第7~8秒:7~8秒流失用戶,估計是盯到了遊戲的加載進度,在100%或某個数字上停止下一瞬間,實在是不耐煩了,什麼個鬼遊戲,半天進不去,走了!

    以上分析是曉衡的個人YY,僅供參考,這裏要說的是前 3 秒流失的用戶大多是條件反射,很難轉化。當用戶將遊戲圖標、遊戲名稱看清了后,大腦產生了思考,再離開的這對我們來說還有機會爭取,讓他們早點看到遊戲首屏,已經花了這5、6秒了,體驗一下再走!

    提升遊戲0.5 ~ 2秒的啟動速度是非常具有價值的,而且小遊戲絕大多數又是 Android 用戶,特別是對需要買量的遊戲來說,時間就是金錢,毫秒必爭。

    引擎插件帶來的好處

    下面我們再來看看,引擎插件具體在那些場景下會帶來比較明顯的性能提供,盡可能充分利用這個機制呢?

    微信公測

    對於個人開發者,使用微信公測功能免費送5000流量,一定要利用好這個機會。將首包資源做到盡量小巧,引擎裁剪、圖片壓縮一定要做足,同時盡量選擇使用量較多的引擎版本號(目前曉衡了解到的,使用較多 Cocos Creator 引擎版本號分佈在:2.0.8 ~ 2.0.10、2.1.3、2.2.0,不過還是要以微信或 Cocos 官方統計為準),這樣容易蹭上已經下載過的遊戲引擎,這對大多數遊戲來說都是適用的。

    中重度遊戲

    中重度遊戲,通常會依賴較多的引擎模塊,比如 RPG 遊戲中的:地圖、角色動畫,會使用TileMap、Spine、DragonBones、Animation 等模塊,還有一些遊戲會使用到物理引擎模塊、碰撞模塊等,完整引擎模塊高達 1.6M。

    隨着微信引擎插件的廣泛普及,以後構建遊戲完全時可以將引擎裁剪到最精簡狀態,大概在550K左右。甚至可以想像到,以後小遊戲平台完全不用上傳引擎代碼,構建時只用配置上使用的什麼引擎,引擎版本號即可。

    中重度遊戲利用引擎插件同樣可以快速進入首屏,首包僅保留炫麗的動效和初始界面,用分治的方式動態下載遊戲當前必要的內容,儘快讓用戶參与到遊戲中去。還有隨着 5G 的到來,中重度遊戲的遊戲資源下載劣勢也會得到改善,對小遊戲更是一件好事。

    遊戲矩陣

    單款小遊戲一般是很難有收益的,甚至是虧本買賣。微信平台,一個小遊戲可以支持10個遊戲的跳轉,目前絕大多數遊戲商廠,都會在小遊戲中集成其它遊戲的入口加大流量,優質的遊戲還會出售遊戲跳轉坑位,有的還價格不菲。個人開發者也意識到了遊戲間跳轉帶來的爆光機會,不少開發者會在微信公眾時,組織邀請好友建立鏈接。

    如果是自家開發的休閑小遊戲,利用引擎插件的啟動增速,再配合上自定義的啟動背景(頭條支持),讓玩家感受不出是在不同遊戲中切換,在矩陣中瞬間穿梭,這也將極大增加遊戲的曝光率,降低流失。

    小結

    劉潤老師說的好:“一切的商業價值,要看是否讓用戶獲益”。

    微信引擎插件不僅讓普通用戶能獲得更好的遊戲體驗,也能讓遊戲開發商能中從獲益。點開即玩的小遊戲,縮短了遊戲產品呈現在用戶手中的時間,極大優化了產品的傳遞價值。

    曉衡是一個搬運工,傳遞有價值的遊戲開發技術,如果覺得本文對你有用,感謝來看個再看或傳遞給朋友。感謝您的閱讀,願我們在前進的道路上“砥礪前行,共同成長!”

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • 賓士傳將開發四款純電動車

    世界級車商賓士(Mercedes-Benz)被報導正在開發全新的電動車平台,並將以此平台為基礎,推出四款純電動汽車。

    ETToday引述外媒《Car Magazine》的報導,表示賓士正以MRA平台為基礎開發一款名為「EVA」的電動車平台,可供後續開發C-Class到S-Class尺碼的各式車款,最高能搭載400公斤的電池組。而在動力方面,後驅車型可能搭載一具402匹馬力的電動馬達,四驅車行可能還會再加上一具120匹馬力或者201匹馬力的馬達。主動懸載、扭力分配、動能回收等功能也將面面俱到。

    該報導表示,賓士官方並未證實這項消息,但將在2018年推出C-Class與E-Class之間的電動轎車,並以此為基礎再行打造一款休旅車。此後還有S-Class和GLS等級的電動車款會問世。《Car Magazine》表示,賓士目標為每年銷售2萬輛電動車,入門車款售價為7萬英鎊起跳。

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • .NET Core 3.0 單元測試與 Asp.Net Core 3.0 集成測試

    .NET Core 3.0 單元測試與 Asp.Net Core 3.0 集成測試

    單元測試與集成測試

    測試必要性說明

    相信大家在看到單元測試與集成測試這個標題時,會有很多感慨,我們無數次的在實踐中提到要做單元測試、集成測試,但是大多數項目都沒有做或者僅建了項目文件。這裡有客觀原因,已經接近交付日期了,我們沒時間做白盒測試了。也有主觀原因,面對業務複雜的代碼我們不知道如何入手做單元測試,不如就留給黑盒測試吧。但是,當我們的代碼無法進行單元測試的時候,往往就是代碼開始散發出壞味道的時候。長此以往,將欠下技術債務。在實踐過程中,技術債務常常會存在,關鍵在於何時償還,如何償還。

    上圖說明了隨着時間的推移開發/維護難度的變化。

    測試框架選擇

    在 .NET Core 中,提供了 xUnit 、NUnit 、 MSTest 三種單元測試框架。

    MSTest UNnit xUnit 說明 提示
    [TestMethod] [Test] [Fact] 標記一個測試方法
    [TestClass] [TestFixture] n/a 標記一個 Class 為測試類,xUnit 不需要標記特性,它將查找程序集下所有 Public 的類
    [ExpectedException] [ExpectedException] Assert.Throws 或者 Record.Exception xUnit 去掉了 ExpectedException 特性,支持 Assert.Throws
    [TestInitialize] [SetUp] Constructor 我們認為使用 [SetUp] 通常來說不好。但是,你可以實現一個無參構造器直接替換 [SetUp]。 有時我們會在多個測試方法中用到相同的變量,熟悉重構的我們會提取公共變量,並在構造器中初始化。但是,這裏我要強調的是:在測試中,不要提取公共變量,這會破壞每個測試用例的隔離性以及單一職責原則。
    [TestCleanup] [TearDown] IDisposable.Dispose 我們認為使用 [TearDown] 通常來說不好。但是你可以實現 IDisposable.Dispose 以替換。 [TearDown] 和 [SetUp] 通常成對出現,在 [SetUp] 中初始化一些變量,則在 [TearDown] 中銷毀這些變量。
    [ClassInitialize] [TestFixtureSetUp] IClassFixture< T > 共用前置類 這裏 IClassFixture< T > 替換了 IUseFixture< T > ,
    [ClassCleanup] [TestFixtureTearDown] IClassFixture< T > 共用後置類 同上
    [Ignore] [Ignore] [Fact(Skip=”reason”)] 在 [Fact] 特性中設置 Skip 參數以臨時跳過測試
    [Timeout] [Timeout] [Fact(Timeout=n)] 在 [Fact] 特性中設置一個 Timeout 參數,當允許時間太長時引起測試失敗。注意,xUnit 的單位時毫秒。
    [DataSource] n/a [Theory], [XxxData] Theory(數據驅動測試),表示執行相同代碼,但具有不同輸入參數的測試套件 這個特性可以幫助我們少寫很多代碼。

    以上寫了 MSTest 、UNnit 、 xUnit 的特性以及比較,可以看出 xUnit 在使用上相對其它兩個框架來說提供更多的便利性。但是這裏最終實現還是看個人習慣以選擇。

    單元測試

    1. 新建單元測試項目

    2. 新建 Class

    3. 添加測試方法

              /// <summary>
              /// 添加地址
              /// </summary>
              /// <returns></returns>
              [Fact]
              public async Task Add_Address_ReturnZero()
              {
                  DbContextOptions<AddressContext> options = new DbContextOptionsBuilder<AddressContext>().UseInMemoryDatabase("Add_Address_Database").Options;
                  var addressContext = new AddressContext(options);
      
                  var createAddress = new AddressCreateDto
                  {
                      City = "昆明",
                      County = "五華區",
                      Province = "雲南省"
                  };
                  var stubAddressRepository = new Mock<IRepository<Domain.Address>>();
                  var stubProvinceRepository = new Mock<IRepository<Province>>();
                  var addressUnitOfWork = new AddressUnitOfWork<AddressContext>(addressContext);
      
                  var stubAddressService = new AddressServiceImpl.AddressServiceImpl(stubAddressRepository.Object, stubProvinceRepository.Object, addressUnitOfWork);
                  await stubAddressService.CreateAddressAsync(createAddress);
                  int addressAmountActual = await addressContext.Addresses.CountAsync();
                  Assert.Equal(1, addressAmountActual);
              }
      • 測試方法的名字包含了測試目的、測試場景以及預期行為。
      • UseInMemoryDatabase 指明使用內存數據庫。
      • 創建 createAddress 對象。
      • 創建 Stub 。在單元測試中常常會提到幾個概念 Stub , Mock 和 Fake ,那麼在應用中我們該如何選擇呢?
        • Fake – Fake 通常被用於描述 Mock 或 Stub ,如何判斷它是 Stub 還是 Mock 依賴於使用上下文,換句話說,Fake 即是 Stub 也是 Mock 。
        • Stub – Stub 是系統中現有依賴項的可控替代品。通過使用 Stub ,你可以不用處理依賴直接測試你的代碼。默認情況下, 偽造對象以stub 開頭。
        • Mock – Mock 對象是系統中的偽造對象,它決定單元測試是否通過或失敗。Mock 會以 Fake 開頭,直到被斷言為止。
      • Moq4 ,使用 Moq4 模擬我們在項目中依賴對象。
    4. 打開視圖 -> 測試資源管理器。

    5. 點擊運行,得到測試結果。

    6. 至此,一個單元測試結束。

    集成測試

    集成測試確保應用的組件功能在包含應用的基礎支持下是正確的,例如:數據庫、文件系統、網絡等。

    1. 新建集成測試項目。

    2. 添加工具類 Utilities 。

      using System.Collections.Generic;
      using AddressEFRepository;
      
      namespace Address.IntegrationTest
      {
          public static class Utilities
          {
              public static void InitializeDbForTests(AddressContext db)
              {
                  List<Domain.Address> addresses = GetSeedingAddresses();
                  db.Addresses.AddRange(addresses);
                  db.SaveChanges();
              }
      
              public static void ReinitializeDbForTests(AddressContext db)
              {
                  db.Addresses.RemoveRange(db.Addresses);
                  InitializeDbForTests(db);
              }
      
              public static List<Domain.Address> GetSeedingAddresses()
              {
                  return new List<Domain.Address>
                  {
                      new Domain.Address
                      {
                          City = "貴陽",
                          County = "測試縣",
                          Province = "貴州省"
                      },
                      new Domain.Address
                      {
                          City = "昆明市",
                          County = "武定縣",
                          Province = "雲南省"
                      },
                      new Domain.Address
                      {
                          City = "昆明市",
                          County = "五華區",
                          Province = "雲南省"
                      }
                  };
              }
          }
      }
    3. 添加 CustomWebApplicationFactory 類,

       using System;
       using System.IO;
       using System.Linq;
       using AddressEFRepository;
       using Microsoft.AspNetCore.Hosting;
       using Microsoft.AspNetCore.Mvc.Testing;
       using Microsoft.EntityFrameworkCore;
       using Microsoft.Extensions.Configuration;
       using Microsoft.Extensions.DependencyInjection;
       using Microsoft.Extensions.Logging;
      
       namespace Address.IntegrationTest
       {
           public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
           {
               protected override void ConfigureWebHost(IWebHostBuilder builder)
               {
                   string projectDir = Directory.GetCurrentDirectory();
                   string configPath = Path.Combine(projectDir, "appsettings.json");
                   builder.ConfigureAppConfiguration((context, conf) =>
                   {
                       conf.AddJsonFile(configPath);
                   });
      
                   builder.ConfigureServices(services =>
                   {
                       ServiceDescriptor descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<AddressContext>));
      
                       if (descriptor != null)
                       {
                           services.Remove(descriptor);
                       }
      
                       services.AddDbContextPool<AddressContext>((options, context) =>
                       {
                           //var configuration = options.GetRequiredService<IConfiguration>();
                           //string connectionString = configuration.GetConnectionString("TestAddressDb");
                           //context.UseMySql(connectionString);
                           context.UseInMemoryDatabase("InMemoryDbForTesting");
      
                       });
      
                       // Build the service provider.
                       ServiceProvider sp = services.BuildServiceProvider();
                       // Create a scope to obtain a reference to the database
                       // context (ApplicationDbContext).
                       using IServiceScope scope = sp.CreateScope();
                       IServiceProvider scopedServices = scope.ServiceProvider;
                       var db = scopedServices.GetRequiredService<AddressContext>();
                       var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
      
                       // Ensure the database is created.
                       db.Database.EnsureCreated();
      
                       try
                       {
                           // Seed the database with test data.
                           Utilities.ReinitializeDbForTests(db);
                       }
                       catch (Exception ex)
                       {
                           logger.LogError(ex, "An error occurred seeding the " + "database with test messages. Error: {Message}", ex.Message);
                       }
                   });
               }
           }
       }
      • 這裏為什麼要添加 CustomWebApplicationFactory 呢?
        WebApplicationFactory 是用於在內存中引導應用程序進行端到端功能測試的工廠。通過引入自定義 CustomWebApplicationFactory 類重寫 ConfigureWebHost 方法,我們可以重寫我們在 StartUp 中定義的內容,換句話說我們可以在測試環境中使用正式環境的配置,同時可以重寫,例如:數據庫配置,數據初始化等等。
      • 如何準備測試數據?
        我們可以使用數據種子的方式加入數據,數據種子可以針對每個集成測試做數據準備。
      • 除了內存數據庫,還可以使用其他數據庫進行測試嗎?
        可以。
    4. 添加集成測試 AddressControllerIntegrationTest 類。

       using System.Collections.Generic;
       using System.Linq;
       using System.Net.Http;
       using System.Threading.Tasks;
       using Address.Api;
       using Microsoft.AspNetCore.Mvc.Testing;
       using Newtonsoft.Json;
       using Xunit;
      
       namespace Address.IntegrationTest
       {
           public class AddressControllerIntegrationTest : IClassFixture<CustomWebApplicationFactory<Startup>>
           {
               public AddressControllerIntegrationTest(CustomWebApplicationFactory<Startup> factory)
               {
                   _client = factory.CreateClient(new WebApplicationFactoryClientOptions
                   {
                       AllowAutoRedirect = false
                   });
               }
      
               private readonly HttpClient _client;
      
               [Fact]
               public async Task Get_AllAddressAndRetrieveAddress()
               {
                   const string allAddressUri = "/api/Address/GetAll";
                   HttpResponseMessage allAddressesHttpResponse = await _client.GetAsync(allAddressUri);
      
                   allAddressesHttpResponse.EnsureSuccessStatusCode();
      
                   string allAddressStringResponse = await allAddressesHttpResponse.Content.ReadAsStringAsync();
                   var addresses = JsonConvert.DeserializeObject<IList<AddressDto.AddressDto>>(allAddressStringResponse);
                   Assert.Equal(3, addresses.Count);
      
                   AddressDto.AddressDto address = addresses.First();
                   string retrieveUri = $"/api/Address/Retrieve?id={address.ID}";
                   HttpResponseMessage addressHttpResponse = await _client.GetAsync(retrieveUri);
      
                   // Must be successful.
                   addressHttpResponse.EnsureSuccessStatusCode();
      
                   // Deserialize and examine results.
                   string addressStringResponse = await addressHttpResponse.Content.ReadAsStringAsync();
                   var addressResult = JsonConvert.DeserializeObject<AddressDto.AddressDto>(addressStringResponse);
                   Assert.Equal(address.ID, addressResult.ID);
                   Assert.Equal(address.Province, addressResult.Province);
                   Assert.Equal(address.City, addressResult.City);
                   Assert.Equal(address.County, addressResult.County);
               }
           }
       }
    5. 在測試資源管理器中運行集成測試方法。

    6. 結果。

    7. 至此,集成測試完成。需要注意的是,集成測試往往耗時比較多,所以建議能使用單元測試時就不要使用集成測試。

    總結:當我們寫單元測試時,一般不會同時存在 Stub 和 Mock 兩種模擬對象,當同時出現這兩種對象時,表明單元測試寫的不合理,或者業務寫的太過龐大,同時,我們可以通過單元測試驅動業務代碼重構。當需要重構時,我們應盡量完成重構,不要留下欠下過多技術債務。集成測試有自身的複雜度存在,我們不要節約時間而打破單一職責原則,否則會引發不可預期後果。為了應對業務修改,我們應該在業務修改以後,進行回歸測試,回歸測試主要關注被修改的業務部分,同時測試用例如果有沒要可以重寫,運行整個和修改業務有關的測試用例集。

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • variable precision SWAR算法

    variable precision SWAR算法

          計算二進制形式中1的數量這種問題,在各種刷題網站上比較常見,以往都是選擇最笨的遍歷方法“矇混”過關。在了解Redis的過程中接觸到了variable precision SWAR算法(以下簡稱VP-SWAR算法),算法異常簡潔,是目前已知的同類方法中最快的。但如果對於位運算不是很熟悉的話,卻不一定容易理解,所以有必要記錄一下。

          下面先看看VP-SWAR算法的完整實現,然後再逐行解釋。

      public int vpSWAR(int i){
        i = (i & 0x55555555) + ((i>>1) & 0x55555555);
        i = (i & 0x33333333) + ((i>>2) & 0x33333333);
        i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F);
        i = (i * 0x01010101) >> 24;
        return i;
      }

          VP-SWAR算法分為四步,第一步

    i = (i & 0x55555555) + ((i>>1) & 0x55555555);
    

          第一步的作用是計算每兩位為一組的二進制形式包含1的個數。要理解這句話,我們需要從二進制的角度看看到底發生了什麼。首先, 0x55555555 的二進製表示為 0101 0101 0101 0101 0101 0101 0101 0101 ,這個数字的規律是基數位為1,偶數位為0。為簡單起見,我們只考慮兩位,總共有四種情況,即:

     

    i b i & b 結果
    00 01 00
    01 01 01
    10 01 00
    11 01 01

           觀察發現, i & (0b01) 是i的基數位對應b的1位,i的偶數位對應着b的0位, i & (0b01) 的結果會將I的偶數位置為0,而基數位保持不變,得到的結果就是i的基數位包含1的個數。 (i >> 1) & 0x55555555 先將i右移一位,也就是將i的基數位對應b的0位,i的偶數位對應着b的1位,然後再與 0x55555555 按位與,計算出來的是i的偶數位包含1的個數。兩個計算結果相加就得到i每兩位為一組中包含的1的數量,我們最後需要的就是這每兩位一組的和。

          第二步是在第一步的基礎上,計算每四位為一組包含1的個數。按照每2位為一組分組用到了 0x55555555 這個數,那麼自然的,按照每4位為一組分組自然就需要 0b0011 這種形式,這就是使用 0x33333333 的原因。理論上, i & (0b0011) 總共有16種情況,但是四位二進制位最多包含4個1,用二進製表示為 0b0100 ,所以經過第一步之後,i最多有5種取值,如下:

    i b i & b 結果
    0000 0011 0000
    0001 0011 0001
    0010 0011 0010
    0011 0011 0011
    0100 0011 0000

     

          觀察發現, i & (0b0011) 得到的是i的低兩位包含的1的個數,  (i >> 2) & 0b0011 )得到的是i的高兩位包含的1的個數,兩個結果相加得到每四位包含的1的個數。注意,這裏並不是說任何數與 0b0011 按位與得到的都是低兩位包含的1的個數,這裏的前提是第一步的計算,因為經過第一步計算之後,每兩位包含多少個1已經記錄了下來,再和 0b0011 按位與才得到正確的結果。例如, 0x0010 & 0x 0011=0x0010 ,但是我們不能說 0x0010 包含兩個1,但是如果 0x0010 是經過第一步的計算得來,那才說明 0x0010 記錄原始數據低兩位有兩個1。

          第三步在第二步基礎上,計算每8位有多少個1,由 0x010x0011 ,很自然想到 0x00001111 ,其對應的32位的十六進制數就是 0x0F0F0F0F

          第四步就很有意思了,它不再是計算每16位包含1的個數,而是直接計算32位包含1的個數。對於32位的數來說,可以將其按每8位一組分為4組,分別用ABCD表示,例如 0x01020304 用這種形式表示為:

     

     

          假設 0x01020304 是經過前三步計算之後得到的結果,那麼要計算其總共包含多少個1,只需計算A+B+C+D。而ABCD表示的是不同的位區間範圍,不能直接相加,該如何快速計算A+B+C+D的值呢?這裏又用到了移位運算,將B、C、D分別左移8位、16位、24位,使其分別與A對齊:

     

           我們發現,將数字i分別左移0位、8位、16位、24位然後相加的結果,就是 i * 0x01010101 ,因為 i + (i << 8) + (i << 16) + (i << 24) = i * (1 + 1 << 8 + 1 << 16 + 1 << 24) = i * 0x01010101 。對於32位数字來說,左移之後超過32位的部分會被捨棄,低位補0,將左移之後得到的四個数字相加,結果的高8位的值就是原32位數包含的1的個數,要得到這個值,只需要將結果右移24位,將值放在低8位即可。

          到這裏,整個算法就結束了,右移的結果就是1的數量。在Redis中,BITCOUNT命令同時使用了查表法和VP-SWAR這兩種方法。當要計算的位數小於128位時,使用查表法,否則使用VP-SWAR算法。其中查表法的做法是,程序先存一個256長度的表,按順序記錄從0-255(即 0b00000000 – 0b11111111) 數中二進制1的個數,然後對於輸入參數每8位查一次表。

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • SQlALchemy session詳解

    系列文章:

    概念

    session用於創建程序和數據庫之間的會話,所有對象的載入和保存都需通過session對象 。

    通過sessionmaker調用創建一個工廠,並關聯Engine以確保每個session都可以使用該Engine連接資源:

    from sqlalchemy.orm import sessionmaker
    
    # 創建session
    DbSession = sessionmaker(bind=engine)
    session = DbSession()

    操作

    session的常見操作方法包括:

    1. flush:預提交,提交到數據庫文件,還未寫入數據庫文件中
    2. commit:提交了一個事務,把內存的數據直接寫入數據庫
    3. rollback:回滾
    4. close:關閉

    在事務處理時,需注意一下兩點:

    1. 在事務處理過程發生異常時,進行rollback操作,否則會在下次操作時報錯:
    Can’t reconnect until invalid transaction is rolled back 
    1. 一般情況下,在一個事務處理完成之後要關閉session,以確保數據操作的準確性。

    建議封裝上下文方法:

    from contextlib import contextmanager
    
    @contextmanager
    def session_maker(session=session):
        try:
            yield session
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

    調用:

    def update_user():
        with session_maker() as db_session:
            db_session.query(Users).filter_by(name='test2').update({'email': 'test2@qq.com'})

    線程安全

    session不是線程安全的,並且我們一般session對象都是全局的,那麼在多線程情況下,當多個線程共享一個session時,數據處理就會發生錯誤。

    為了保證線程安全,需使用scoped_session方法:

    db_session = scoped_session(sessionmaker(bind=engine))

    內部原理

    session對象包含了三個重要的部分:

    1. 標識映射(Identity Map)
    2. 對象的狀態 / 狀態跟蹤
    3. 事務

    標識映射

    標識映射是與ORM關聯的集合,通過標識映射保證了數據庫操作的準確性。

    具體的實現原理是:維護一個Python字典(IdentityMap),關聯這個Session對象到數據庫ID的映射,當應用程序想要獲取一個session對象時,若該對象不存在,標識映射會加載該對象並緩存,若該對象已存在,則直接獲取。這樣的好處是:

    1. 已經被請求過的session對象緩存下來,不需要連接加載多次,造成額外的開銷;
    2. 避免了數據不一致

    狀態跟蹤

    一個Session對象從創建到銷毀,依次經歷四種狀態,分別是:

    1. Transient:剛new出來的對象,還不在會話中,也沒有保存到數據庫。
    2. Pending:transient的對象調用add后,就會變成pending狀態,這時會加入sqlalchemy的監管範圍,數據並未更新到數據庫。
    3. Persistent:該狀態表明數據庫里已經記錄了該對象,在兩種情況下對象處於該狀態:一是通過flush()方法刷新pending對象,二是從數據庫query()得到對象。
    4. Detached:在會話中的事務提交之後,所有的對象都將是Detached狀態。

    所謂的狀態跟蹤,就是跟蹤以上四個狀態,保證數據的準確性並在合理的時機丟棄對象以保證合理開銷,那麼具體是怎麼實現的呢?

    我們可以看到,只有在pending狀態時,對象的內存數據和數據庫中的數據不一致,在Persistent狀態時,內存數據和數據庫數據已經一致,那麼此後任意時刻丟棄該對象數據都是可以的,這時就需要找個合適的時機丟棄對象,過早或過晚都有其缺陷。於是,就讓垃圾回收器來做決定,在內存不夠的時候釋放對象,回收內存。

    Session對象採用了弱引用機制,所謂弱引用,就是說,在保存了對象的引用的情況下,對象仍然可能被垃圾回收器回收。在某一時刻通過引用訪問對象時,對象可能存在也可能不存在,如果對象不存在,就重新從數據庫中加載對象。而如果不希望對象被回收,只需要另外保存一個對象的強引用即可 。

    session對象包括三個屬性:

    1. new:剛加入會話的對象
    2. dirty:剛被修改的對象
    3. deleted:在會話中被刪除的對象

    三個屬性共同的特點就是內存的數據和數據庫數據不一致,也就是對象處於pending狀態,這也就表明了session保存了所有對象處於pending狀態的強引用。

    以上。

    代碼可參照:

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

  • spring 是如何注入對象的和bean 創建過程分析

    文章目錄:

    1. 【本文】spring 是如何注入對象的

    首先需要知道一個大致實現

    • 這個注入過程肯定是在 BeanPostProcessor 中實現的

    • spring 是在 beanFactory.getBean 進行 bean 實例化的,即懶加載

    • 根據第二條,也就是說在 getBean 的時候才會去調用所有 BeanPostProcessor

    • 第二篇文章說到,BeanFactory 的 refresh 過程只是註冊 BeanPostProcessor,真正執行在 getBean 方法中

    • MergedBeanDefinitionPostProcessor 也是一種 BeanPostProcessor 它重新弄了個一個生命周期函數,替代了 BeanPostProcessor 默認的生命周期函數,這麼看吧,我貼一小段源碼

      for (BeanPostProcessor bp : getBeanPostProcessors()) {
          if (bp instanceof MergedBeanDefinitionPostProcessor) {
              MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
              bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
          }
      }

      它允許你在非 BeanFactoryProcess 中去修改 Bean 定義

    • InstantiationAwareBeanPostProcessor 也是一種 BeanPostProcessor 它也重新定義了一個生命周期函數,它允許把屬性值注入到屬性對象中

    @Autowired 加載定義的過程

    我們先不看 bean 的創建過程,就看 MergedBeanDefinitionPostProcessor 的實現子類,這裏看名字猜測 AutowiredAnnotationBeanPostProcessor 應該就是干這件事的,所以我們接下來可以直接看 AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition 方法的代碼。

    順着方法的調用,可以知道在 buildAutowiringMetadata 是真正查找這些註解的地方,最後 checkConfigMembersMember 註冊進了 bean 定義,具體如何查找的讀者自行查看源碼。

    這裏只是將 Member 註冊進了 bean 定義,真正實例化在填充 Bean 的過程中,下面說到 bean 的創建過程可以知道是何時注入的。

    Bean 的創建過程

    前面說到 spring 是在 getBean 的過程中進行 Bean 創建的,創建 bean 分為幾個步驟

    1. 獲取 bean 定義
    2. new Bean()
    3. 執行生命周期函數 (前)
    4. 創建依賴項
    5. 填充 bean
    6. 執行生命周期函數(后)

    入口為 BeanFactory.getBean ,BeanFactory 的實現類為 DefaultListableBeanFactory 這些你可以在 BeanFactory 的 refresh 過程中找到

    根據源碼,如果 bean 還不存在時,就會執行 bean 的創建流程

    獲取 bean 定義在這段源碼中

    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

    緊跟着,根據 Bean 定義搜索其依賴項,並創建 bean ,可以看出是遞歸創建 bean

    String[] dependsOn = mbd.getDependsOn();
    for (String dep : dependsOn) {
        getBean(dep);
    }

    然後就創建 bean 了

    if (mbd.isSingleton()) {
        createBean(beanName, mbd, args);
    }
    
    // 真正的執行在 doCreateBean 過程中
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);

    創建 bean 第一步 new Bean

    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }

    創建 bean 第二步,執行所有的 processor ,包含 MergedBeanDefinitionPostProcessor ,所以在這一步註冊注入選項

    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

    創建 bean 第三步,填充 bean ,這裏做的 @Autowired 注入

    populateBean(beanName, mbd, instanceWrapper);

    最終的處理過程在 AutowiredAnnotationBeanPostProcessor 的 postProcessPropertyValues 函數中

    metadata.inject(bean, beanName, pvs);

    因為在前面已經獲取過依賴項,並且把其丟進了容器,所以這裡是直接用反射寫進去就可以了

    創建 bean 第四步,初始化 bean ,這裡有一個方法注入,方法注入原來發生在初始化 bean 過程中,還有就是生命周期函數執行了,包含 BeanPostProcessor 的前置後置生命周期,初始化方法等

    小說明 :AutowiredAnnotationBeanPostProcessor 即是 一個 MergedBeanDefinitionPostProcessor 也是一個 InstantiationAwareBeanPostProcessor

    一點小推廣

    創作不易,希望可以支持下我的開源軟件,及我的小工具,歡迎來 gitee 點星,fork ,提 bug 。

    Excel 通用導入導出,支持 Excel 公式
    博客地址:
    gitee:

    使用模板代碼 ,從數據庫生成代碼 ,及一些項目中經常可以用到的小工具
    博客地址:
    gitee:

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

    【其他文章推薦】

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

    網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!