巴西海岸漏油原因仍是謎 成千上萬志工「挖黑泥」

摘錄自2019年10月21日自由時報報導

巴西日前發生大規模漏油事件後,對當地北部約2100公里、橫跨數州的海岸線造成嚴重破壞,雖已進入調查,但至今漏油原因尚未查明,而當地政府因未積極採取行動,遭當地環保團體抨擊;所幸,已有成千上萬的志工在受污染區域「挖黑泥」,將遍布海灘的「油污」慢慢除去,而這些志工僅在伯南布哥州(Pernambuco)就已經清出30噸油污。

油污從9月2日開始出現,而這些污染物質經檢驗,已證實為石油原油。海洋學家阿勞霍(Maria Christina Araujo)指出,「此次漏油對受污染區域當地生物的破壞可能將無法彌補,需要數年才能逐漸恢復當地生態系統。」而巴西環境與可再生資源研究所(Ibama)也證實,有15隻海龜和2隻鳥被油污殺死,且有照片佐證這些生物遭黑色油污覆蓋致死,而巴西享譽世界的的珊瑚礁也受到油污的破壞。

照片來源:Kleber from Burgos / WWF-Brasil

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

【其他文章推薦】

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

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

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

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

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

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

【案例演示】JVM之強引用、軟引用、弱引用、虛引用

1.背景

想要理解對象什麼時候回收,就要理解到對象引用這個概念,於是有了下文

2.java中引用對象結構圖

3.引用詳解

3.1.什麼是強引用

a.當內存不足,JVM開始垃圾回收,對於強引用的對象,就算是出現了00M也不會對該對象進行回收,死都不收。

b.強引用是我們最常見的普通對象引用,只要還有強引用指向一個對象,就能表明對象還“活着”,垃圾收集器不會碰這種對象。

在Java中最常見的就是強引用,把一個對象賦給一個引用變量,這個引用變量就是一個強引用。

當一個對象被強引用變量引用時,它處於可達狀態,它是不可能被垃圾回收機制回收的,即使該對象以後永遠都不會被用到JVM也不會回收。

因此強引用是造成Java內存泄漏的主要原因之一

c.對於一個普通的對象,如果沒有其他的引用關係,只要超過了引用的作用域或者顯式地將相應(強)引用賦值為null,一般認為就是可以被垃圾收集的了〈當然具體回收時機還是要看垃圾收集策略)。

案例:

package com.wfd360.demo03GC.referDemo;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 12:12
 * @description
 */
public class StrongRefer {
    /**
     * 強引用的理解
     *
     * @param args
     */
    public static void main(String[] args) {
        Object obj1 = new Object();
        // 建立強引用
        Object obj2 = obj1;
        // 觀察obj1 和 obj2 的各種內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("obj2=" + obj2);
        // obj1創建可以回收的條件
        obj1 = null;
        // gc回收
        System.gc();
        // 觀察各對象情況
        System.out.println("obj1=" + obj1);
        System.out.println("obj2=" + obj2);
    }
}

View Code

 從測試結果課程看出,obj1的實際對象別沒有回收;

3.2.什麼是軟引用

a.軟引用是用來描述一些還有用但並非必需的對象,需要用java.lang.ref.SoftReference類來實現。

b.對於軟引用關聯着的對象,在系統將要發生內存溢出異常之前,將會把這些對象列進回收範圍之中進行第二次回收。如果這次回收還沒有足夠的內存,才會拋出內存溢出異常。在JDK1.2之後,提供了Soft Reference類來實現軟引用。

c.軟引用通常用在對內存敏感的程序中,比如高速緩存就有用到軟引用,內存夠用的時候就保留,不夠用就回收!

案例:

package com.wfd360.demo03GC.referDemo;

import java.lang.ref.SoftReference;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 12:12
 * @description
 */
public class SoftRefer {

    /**
     * 軟引用的理解
     * 通過設置jvm參數,在不同的條件下觀察
     *
     * @param -Xms5m -Xmx5m -XX:+PrintGCDetails
     * @param args
     */
    public static void main(String[] args) {
        // 測試內存充足(不回收軟引用)
        //testSoftReferNOGc();
        // 測試內存不充足(回收軟引用)
        testSoftReferGc();
    }

    /**
     * 模擬內存充足的情況
     */
    public static void testSoftReferNOGc() {
        Object obj1 = new Object();
        // 建立軟引用
        SoftReference softRefer = new SoftReference<>(obj1);
        // 觀察內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("softRefer=" + softRefer.get());
        // obj1創建可以回收的條件
        obj1 = null;
        // gc回收
        System.gc();
        // 再次觀察內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("softRefer=" + softRefer.get());
    }

    /**
     * 模擬內存不足
     * 1.設置較小的堆內存
     * 2.創建大對象
     * 3.jvm參
     * -Xms5m -Xmx5m -XX:+PrintGCDetails
     */
    public static void testSoftReferGc() {
        Object obj1 = new Object();
        // 建立軟引用
        SoftReference softRefer = new SoftReference<>(obj1);
        // 觀察內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("softRefer=" + softRefer.get());
        // obj1創建可以回收的條件
        obj1 = null;
        try {
            byte[] bytes = new byte[6 * 1024 * 1024];
        } catch (Throwable e) {
            System.out.println("===============>error:" + e.getMessage());
        } finally {
            // 再次觀察內存地址
            System.out.println("obj1=" + obj1);
            System.out.println("softRefer=" + softRefer.get());
        }
    }
}

View Code

內存充足測試結果:

 內存不充足測試結果:

 實際案例

假如有一個應用需要讀取大量的本地數據(圖片、通訊率、臨時文件等):

如果每次讀取數據都從硬盤讀取則會嚴重影響性能,

如果一次性全部加載到內存中又可能造成內存溢出。

此時使用軟引用可以解決這個問題。

設計思路是:用一個HashMap來保存數據的路徑和相應數據對象關聯的軟引用之間的映射關係,在內存不足時,

JVM會自動回收這些緩存數據對象所佔用的空間,從而有效地避免了00M的問題。

Map<String,SoftReference>imageCache=new HashMap<String,SoftReference>();

 3.3.什麼是弱引用

a.弱引用也是用來描述非必需對象的,但是它的強度比軟引用更弱一些,被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。

b..當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。在JDK1.2之後,提供廣Weak Reference類來實現弱引用。

c.弱引用需要用Java.lang.ref.WeakReference類來實現,它比軟引用的生存期更短.

案例:

package com.wfd360.demo03GC.referDemo;

import java.lang.ref.WeakReference;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 12:12
 * @description
 */
public class WeakRefer {

    /**
     * 弱引用的理解
     *
     * @param args
     */
    public static void main(String[] args) {
        Object obj1 = new Object();
        // 建立弱引用
        WeakReference softRefer = new WeakReference<>(obj1);
        // 觀察內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("softRefer=" + softRefer.get());
        // obj1創建可以回收的條件
        obj1 = null;
        // gc回收
        System.gc();
        // 再次觀察內存地址
        System.out.println("obj1=" + obj1);
        System.out.println("softRefer=" + softRefer.get());
    }

}

View Code

 擴展知識-WeakHashMap

查看API介紹:

 測試代碼:

package com.wfd360.demo03GC.referDemo;

import java.util.HashMap;
import java.util.WeakHashMap;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 5:10
 * @description <p>
 * 弱引用引用之:WeakHashMap
 * 以弱鍵 實現的基於哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。
 * 更精確地說,對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成為可終止的,被終止,
 * 然後被回收。丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行為與其他的 Map 實現有所不同。
 * </p>
 */
public class WeakReferMap {
    /**
     * 測試 HashMap 與 WeakHashMap 區別
     * 測試邏輯:
     * 1.創建不同的map
     * 2.創建key  value值
     * 3.放入各自的map,並打印結果
     * 4.將key設置為null,並打印結果
     * 5.手動GC,並打印結果
     *
     * @param args
     */
    public static void main(String[] args) {
        hashMapMethod();
        System.out.println("--------華麗的分割線--------");
        weakHashMapMethod();
    }

    /**
     * HashMap測試(強引用)
     */
    private static void hashMapMethod() {
        HashMap<String, String> map = new HashMap<>();
        String key = "key1";
        String value = "HashMap-value";

        map.put(key, value);
        System.out.println(map);

        key = null;
        System.out.println(map);

        System.gc();
        System.out.println(map);
    }

    /**
     * 若引用(WeakHashMap測試)
     */
    private static void weakHashMapMethod() {
        WeakHashMap<String, String> map = new WeakHashMap<>();
        // 注意這裏的new一個字符串與直接寫key="key2"對測試結果是有區別的,詳細原因可以看之前講的內存分配
        String key = new String("key2");
        String value = "WeakHashMap-value";

        map.put(key, value);
        System.out.println(map);

        key = null;
        System.out.println(map);

        System.gc();
        System.out.println(map);

    }

}

View Code

測試結果:

 從測試結果可以看出:弱引用的map數據已經被回收。

 擴展知識-ReferenceQueue引用隊列

 代碼:

package com.wfd360.demo03GC.referDemo;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 7:23
 * @description
 */
public class QueueRefer {
    /**
     * 測試弱引用回收前,把數據放入隊列中
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Object obj1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue();
        // 當GC釋放對象內存的時候,會將引用加入到引用隊列
        WeakReference<Object> weakReference = new WeakReference<>(obj1, referenceQueue);

        System.out.println(obj1);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());

        System.out.println("--------華麗的分割線--------");
        obj1 = null;
        System.gc();
        Thread.sleep(500);

        System.out.println(obj1);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());
    }

}

View Code

採用弱引用的方式測試結果:

從測試結果可以看出,需要回收的對象已經進入隊列。

 採用軟引用的方式測試結果:

 從測試結果可以看出,軟引用,沒有到達回收的條件,並沒有進行回收,也不會進入隊列;

3.4.什麼是虛引用

1.虛引用需要java.lang.ref.PhantomReference類來實現。

2.與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有

虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收,它不能單獨使用也不能通過它訪

問對象,虛引用必須和引用隊列(ReferenceQueue)聯合使用。

3.虛引用的主要作用是跟蹤對象被垃圾回收的狀態。僅僅是提供了一種確保對象被finalize以後,做某些事情的

機制。PhantomReference的get方法總是返回null,因此無法訪問對應的引用對象。其意義在於說明一個對象己

經進入俑finalization階段,可以被gc回收,用來實現比finalization機制更靈活的回收操作。

4.設置虛引用關聯的唯一目的,就是在這個對象被收集器回收的時候收到一個系統通知或者後續添加

進一步的處理。Java技術允許使用finalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。

代碼:

package com.wfd360.demo03GC.referDemo;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 7:44
 * @description
 */
public class PhantomRefer {
    /**
     * 虛引用測試
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Object obj1 = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue();
        PhantomReference<Object> phantomReference = new PhantomReference<>(obj1,referenceQueue);

        System.out.println(obj1);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());

        System.out.println("--------華麗的分割線--------");

        obj1 = null;
        System.gc();
        Thread.sleep(500);

        System.out.println(obj1);
        System.out.println(phantomReference.get());
        System.out.println(referenceQueue.poll());
    }

}

View Code

測試結果:

4.重要總結

對象是否存活判斷流程:

1.可達性分析,看是否有GC Roots的引用鏈,如果沒有將做第一次標記;

2.檢查是否需要執行finalize()方法,

如果沒必要(之前執行過了),直接回收內存;

如果要執行finalize()方法,這個時候對象如果再次建立引用鏈(唯一自救機會),對象不會被回收,否則直接回收;

總結:

1.對象回收滿足兩個條件:

a.沒有引用鏈。

b.回收前會執行finalize()方法,如果執行finalize(),沒有再次建立連接(如果重新與引用鏈上的任意對象建立連接,例如給對象賦值,該對象都不會被回收)

2.在gc回收前會執行finalize()方法,只執行一次,並且是異步執行不保證執行成功,線程優先級低

代碼演示:

package com.wfd360.demo03GC.referDemo;

/**
 * @author 姿勢帝-博客園
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 06/20 8:34
 * @description
 */
public class FinalizeGC {
    public static FinalizeGC obj1 = null;

    /**
     * 重寫finalize方法
     * @throws Throwable
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("執行finalize方法");
        // 自救,在回收時建立引用鏈
        FinalizeGC.obj1 = this;
    }

    public static void main(String[] args) throws InterruptedException {
        obj1  = new FinalizeGC();

        obj1 = null;
        System.gc();
        Thread.sleep(600);
        System.out.println("第一次自救成功:"+obj1);

        obj1 = null;
        System.gc();
        Thread.sleep(600);
        System.out.println("第二次自救失敗,不會再次執行finalize方法:"+obj1);
    }
}

View Code

測試結果:

 完美!

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

【其他文章推薦】

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

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

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

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

新北清潔公司,居家、辦公、裝潢細清專業服務

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

.NET Core Hangfire周期性作業調度問題

前言

四月中旬Hangfire團隊發布了1.7.11版本,在使用周期性作業調度過程中發現一個問題,這個問題應該一直未解決,故做此記錄,希望遇到的童鞋根據項目業務而避開這個問題。

周期性作業調度

我們依然是在控制台中進行測試,下載所需包請參考官方文檔,這裏不再敘述,首先我們在內存中存儲數據,如下:

var storageOpts = new MemoryStorageOptions();

GlobalConfiguration.Configuration.UseMemoryStorage(storageOpts);

using var server = new BackgroundJobServer();

RecurringJob.AddOrUpdate("job1", () => Print1(), "*/10 * * * * *", TimeZoneInfo.Local);

RecurringJob.AddOrUpdate("job2", () => Print2(), "*/10 * * * * *", TimeZoneInfo.Local);

RecurringJob.AddOrUpdate("job3", () => Print3(), "*/10 * * * * *", TimeZoneInfo.Local);
public static void Print1()
{
    Console.WriteLine("start1");
}

public static void Print2()
{
    Console.WriteLine("start2");
}

public static void Print3()
{
    Console.WriteLine("start3");
}

Hangfire已支持秒級(1.7+)周期作業調度,如上代碼,我們每隔10秒執行上述3個作業,打印如下:

 

基於內存存儲間隔10秒執行對應作業,根據上述打印結果來看沒有問題,接下來我們使用SQLite來存儲作業數據看看,首先下載Hangfire.SQLite包,針對控制台需進行如下配置

GlobalConfiguration.Configuration.UseSQLiteStorage("Data Source=./hangfire.db;");

當我們啟動控制台時一定會拋出如下異常,其異常旨在表明需要SQLite驅動

我們去下載微軟官方針對SQLite的驅動(Microsoft.Data.Sqlite)

 接下來我們將發現對於每一個作業都會重複執行多次,如下:

猜測只會在SQLite數據庫中才會存在問題吧,為了解決這個問題,做了一點點嘗試,但還是無法從根本上完全解決,我們知道Hangfire服務的默認工作數量為當前機器的處理器數量乘以5即(Environment.ProcessorCount * 5),那麼我們嘗試給1是不是可以規避這個問題

var options = new BackgroundJobServerOptions()
{
    WorkerCount = 1
};

using var server = new BackgroundJobServer(options);

 

上述設置后,我們可以看到貌似只執行了一次,但是這種情況還是是隨機的並不靠譜,比如多執行幾次看看,會出現如下可能情況

 

沒招了,找了下官方issue列表,發現此問題(https://github.com/mobydi/Hangfire.Sqlite/issues/2)一直處於打開狀態並未得到解決,所以要麼看看能否根據項目業務規避這個問題或者下載源碼自行調試解決

總結

本文是在使用Hangfire過程中發現SQLite數據庫出現的問題,因針對Hangfire的SQLite具體實現並不是官方團隊所提供,所以暫不能確定到底是Hangfire.SQLite包提供者的問題,根據issue描述大概率是Hangfire的一個bug,希望在SQLite存儲作業等數據存在的問題引起使用者注意。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

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

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

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

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

本田將研發新型小型混動車 比同類車省30%燃油

本田汽車公司日前通過官方網站宣佈,將研發新型的小型

據介紹,新型混合動力汽車主要是在動力系統上加以改進,採用了電動機帶動汽車的電動汽車模式(EV),這將比其它同類汽車再節省燃油30%。本田公司計畫從明年開始對新款“飛度”汽車裝配此種動力模式。在市場上將會與豐田公司的“AKUA”小型混合動力汽車形成競爭。

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

【其他文章推薦】

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

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

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

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

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

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

豐田7款新能源車型亮相廣州車展

近日,將在豐田廣州車展的5.1館的約1500平米的展臺上共展出概念車以及國產、進口車型共計46輛,其中豐田的混合動力車型將成為本次車展上的重點,同台亮相的有12款為混合動力車型(HEV)、外插充電式混合動力車型(PHEV)以及型(EV),與此同時還包括了1款預計2013年進入中國市場的亞洲首發車和中國首發的新款雷克薩斯LS600hL混動加長版車型。

雲動雙擎

●混合動力概念車

“雲動雙擎”概念車作為豐田“雲動計畫”中所包涵的開發國產混合動力總成這一重要內容的國產混合動力的象徵而誕生,量產車將於2015年左右推出。長軸距延展出的流暢曲線,造就了獨具魅力的整體造型,更突顯了高級的質感。搭載豐田最先進,也是世界最高水準的混合動力系統,同時集高水準的行駛性能以及超凡品質於一身,既實現了“環保駕駛”,又打造了無限的駕乘樂趣。

TOYOTA DEAR“親”

●小型概念車

豐田的全新小型概念車—TOYOTA Dear ~親~,讓小型車也能迸發激情。TOYOTA Dear ~親~是為了贏得更多中國用戶而設計研發的小型概念車。這款概念車計畫在2013年投放中國市場,使豐田在中國的全線車型更加充實,“TOYOTA Dear ~親~”也將成為豐田推進全球戰略的核心車型。考究的外形,大膽而又動感的線條,加以寬敞的車內空間,完全打破了對小型車的傳統印象。車內配備的光感測器等先進技術更增添了行車的樂趣,讓人們對豐田的小型車充滿期待。

PRIUS PLUG-IN HYBRID Concept

●外插充電式混合動力概念車

PRIUS PLUG-IN HYBRID Concept是以鋰離子電池作為驅動電池,以第3代PRIUS普銳斯為原型,可使用家用電源進行外部充電的外插充電式混合動力車。

該車可以選擇純電動模式或混合動力模式行駛,能夠更加充分地使用電能而且不受電池剩餘量和充電設施完善情況的限制,通過減少不可再生資源消耗和二氧化碳排放來防止大氣污染。它的目標是每公升汽油可行駛55公里以上*(二氧化碳排放量42g/km以下),並在充滿電的情況下作為純電動車的行駛距離為20km以上。充電時,該車在100V電源下約180分鐘,200V電源下約100分鐘即可充滿。

2012年,豐田與中國汽車技術研究中心共同在天津開展的實證行駛實驗圓滿結束,預計2012年內提前試銷。

NS4

●外插充電式混合動力概念車

豐田最新一代外插充電式混合動力概念車,兼備高燃油經濟性以及澎湃動力,採用先進的安全技術和“人、車與社會緊密相連”技術,全面展示了豐田在安全與新能源領域的技術成果。

前臉設計獨特,展示淩厲中的魅惑風情,低重心造型凸顯感性魅力,達到令人驚豔的設計效果。配備革新性的HMI(Human Machine Interface,人機交互系統及雙顯示幕),實現輕鬆操控。

配備新一代PCS預碰撞安全系統和行人防撞預警系統等先進技術,大幅提高行車安全性;配有3台後攝像頭,確保後方視野開闊,減少視線移動。

FT-EV III

●電動概念車

豐田FT-EV系列的第三代概念車,適於短途行駛的“超小型輕量設計”電動概念車。

電動車將有望替代化石燃料的電能作為動力源,在行駛中不會排出二氧化碳,未來會成為非常重要的環保汽車。動力系統配備鋰電池,預計一次充電可以行駛105公里,非常適合短途行駛。

車身長度雖然只有3.1米,寬也不到1.7米,卻實現了可供4人乘坐的寬敞空間。

RAV4 EV

●電動概念車

1998年,中國國家科學技術部在廣東省汕頭市南澳島實施電動車行駛實驗,豐田為其提供了RAV4 EV作為行駛實驗車,該車搭載的鎳氫電池可實現達200km的續航距離。

豐田早在40年前就開始潛心研發能夠普及的新能源技術,混合動力技術是目前全球最成熟最先進的環保技術。2012年1月~10月混合動力車全球累計銷量為102.8萬輛,年度銷量首次突破100萬輛大關,今年在豐田銷售的車輛中,混合動力車已經占到其全球銷量的14%。與此同時,豐田混合動力車自1997年上市以來,實現全球累計銷量達到460.3萬輛。截至2012年10月末,在全球範圍內混合動力車與車輛尺寸、及動力性能相同的汽油車相比,累計節約石油約110億升,同時減少約3000萬噸二氧化碳的排放。

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

【其他文章推薦】

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

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

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

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

新北清潔公司,居家、辦公、裝潢細清專業服務

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

上汽榮威550插電式混動車將於2012年年底投放

繼中國首款量產榮威E50之後,榮威品牌的另一款新能源車榮威550插電式混合動力車將於2012年年底投放。

榮威550插電式混合動力車基於榮威550而開發,外觀上與榮威550沒有區別。據透露,榮威550插電式混合動力車搭載的是一款1.5VCT發動機,電池方面採用的則是磷酸鐵鋰電池。

榮威550插電式混合動力車最早亮相於今年的北京車展。此前,上汽乘用車相關負責人透露,這款節油率超過50%,百公里油耗不到3升的插電式混合動力車將在今年年底上市。

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

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

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

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

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

淺談async/await

小明用async/await寫了幾年的異步方法,但總沒有完全理解裏面的機制,他決定去請教鄰居小花。

小花聽了小明的描述后說:首先你要明白異步的根本是什麼?大白話解釋異步就是:拉一個人(線程)幫着做一些耗時的事(下載、讀寫數據庫等),我先做別的事了(退出線程),等做好了和我說下,我再繼續做後面的事(恢復上下文)。

小花看到小時還沒有明白,就說:我舉個簡單例子幫你理解吧,假如有兩個方法A和B,A調用B方法,B方法是一個異步方法,這時A不等待B執行完,如圖:

現在兩個方法被分隔幾個小塊,await關鍵字其實就用來隔開同步和異步,上面的方法執行流程如下:

A調用B方法后,B方法在未執行到await之前還是同步方法,比如輸出Sub1還是在當前線程中執行,當方法遇到await后,就會把await后的方法放到新的線程中執行,當前線程則退出函數,由於調用的地方並沒有await,則主線程會繼續執行並輸出Part2,然後結束。等新線程中Thread.Sleep(5000)執行完后,會執行到Console.Write(“Sub2”);這一行代碼會回到原來的線程執行,其實遇到await時會捕獲當前線程的執行上下文,然後給到新線程,新線程在執行完耗時操作后,會判斷之前捕獲到的執行上下方是否為null,如果不為null,則會在上下文中恢復並執行後面的方法,其實就是通過Tak的ContineWith方法註冊回調,如圖:

小明好像聽懂了一些說:現在A方法調用DoSomethingAsync()並沒有等待,如果A方法需要這個方法執行完才能繼續執行,是不是要在DoSomethingAsync()前面加上await?小花回答是,並說:方法只要遇到await,就會把後面的方法給新線程執行,然後線程退出去執行別的方法,等新線程執行完后再通知當前線程恢復上下文繼續執行,如圖:

小明又問:你說異步方法執行完后,後面的方法會在原來的線程中恢復並執行,如果我還想在新線程中繼續執行剩下的代碼,要怎麼辦呢?小花說問的好,await調用新線程執行耗時操作時默認會捕獲當前上下文,如果不想捕獲,則可以調用ConfigAwait(false)方法,如圖:

執行流程如下:

小花補充到,上線提到的線程1、線程2、線程3等不一定準確,因為異步的回調是使用線程池中的線程,所以回調有可能還在原來線程中執行,這個主要看操作系統的調度。

小明滿意的點點頭又問:我經常聽同事說用異步方法會死鎖,這又是為什麼呢?小花聽了說,他們肯定是在調用異步方法的時候使用.Result(),如圖:

小花指着圖解釋說:上面的代碼task.Result()會阻塞線程等待task返回結果,DoSomethingAsync方法在執行完Thread.Sleep(5000)后,發現捕獲到的上下文不為空,則會嘗試將Console.Write(“Sub2”)這行代碼交由調用線程去執行,而這時調用線程還在等待,就這樣互相卡着對方,就造成了死鎖,如圖:

小明點了點頭又問:那要怎麼避免呢?小花說出現這種情況也和框架有關,像WinForm為了讓所有UI操作都在主線程中執行,就添加了一個SynchronizationContext類實例用以表示當前上下文,而像控制台等項目這個SynchronizationContext實例默認為null,所以即使使用.Result也不會死鎖。但最好使用異步的時候不要用.Result,可以使用ConfigAwait(false)指明不捕獲上下文,或所有的方法全部異步到底。

 

小明聽完滿意地回到自己的隔間。

 

更多精彩,請關注我的公眾號:

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

【其他文章推薦】

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

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

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

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

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

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

代碼和設計是如何一步步腐化的

經歷了幾個從商業角度來看或成功或失敗的項目,都會發現代碼、設計都會慢慢地、在不經意間腐化。而且有一個項目開始的時候,架構是經過精心設計的,也有較為嚴格的代碼規範,並且通過靜態代碼檢查來盡量保證代碼的質量,連code review都有一個可供參考的checklist。但半年一年之後,還是會發現,很多代碼都已經臃腫走樣,到處都是複製粘貼,動輒好幾千行代碼的模塊,能 work、但不 right的代碼。

getting it work is easy
getting it right is hard

不禁想問問代碼和設計是如何一步步腐化的?

本文地址:https://www.cnblogs.com/xybaby/p/13173047.html

代碼如何開始腐爛

其實大家都聽說過 clean code,但不一定真正意識到其重要性,且知道並不等同於做到,而時間更是一把殺豬刀,讓程序員禿了,讓代碼爛了。

一個新項目開始的時候,大家都是滿懷壯志,期待靈活可復用的架構,期待成功的產品。與此同時,敏捷開發告訴我們不要過度設計,當然,本身也是很難預料到以後需求變化的方向,於是應該等到第一次變化的時候才去考慮如何重構以應對這一類型的變化。但問題很可能就會出現在這裏。

也就是說,也許哪一天,當我們需要加一個新功能的時候,會發現原來的設計和代碼不是很方便增加這個新功能。當然,我們不應該過多苛責之前的設計,因為以前沒有預料到這個新功能,也就沒有在這個地方引入抽象。這個時候有兩種解決辦法:第一種是重構術,就是加功能之前先了解、重構已有的代碼,比如調整一下類的基礎體系、抽象出基類、或者引入一個間接層以隔離變化。另一種則是修補術,在現有的函數中加一個 if-else(或者 switch case)、在現有的類中加幾個特殊字段。這兩種方法都能解決問題,修補術治標,重構術治本,但顯然,治標來得更快,治本對程序員的要求更高。

什麼時候程序員會選擇修補術而不是重構術呢?

也許這個程序員看過 clean code、refactor,精通設計模式和面向對象,也非常希望維護一份漂亮的代碼。但我們知道,重構是需要時間的,而且還可能引入bug。也許重構耗費的時間就超過了用修補術 workaround 的時間,就短期來說,修補術的性價比是更高的。那麼長遠來說呢,也許重構術的性價比更高?可是只顧眼前、及時行樂是人的本能,走捷徑、偷懶是無時不存在的誘惑。當然,也許有追求的程序員會抵制這種誘惑,但是社會心理學告訴我們,在壓力、干擾面前我們很難理智思考,自控力也會失效。時間、進度壓力就是垂懸在程序員頭上的達摩克利斯之劍,這壓力可能讓人失眠、讓人頭禿,寫點垃圾代碼似乎也無可厚非。

況且,重構還可能引入bug,重構的前提是要有完備的測試機制,單元測試、功能測試、集成測試一個都不能少。可是,理想很豐滿,現實很骨感,單元測試覆蓋率往往不足,而且還可能依靠手動回歸測試。把代碼重構好了可能壓根沒人知道,沒人來感謝你、給你點個贊,但萬一重構出了bug呢,大家都會收到事故報告,說不定還會影響KPI?不求有功但求無過,Leader、經理是否認可重構的價值,也很大程度影響組員對於重構的积極性。

當然,增加新功能的也許是一個新手,新手加入團隊后,一般就是從維護某個模塊,實現一些小需求入手。新手有可能水平本身就不行,而且業務邏輯和代碼都是陌生的,如果缺乏完善的文檔以及足夠的掌握,新手是萬萬不敢重構的,修補術是最自然的選擇,複製、粘貼、稍微修改一下、build、run,成功啦!又實現了一個需求!你知道,新人是急於證明自己的,快速的實現一個又一個需求是證明自己的最佳辦法。

你有可能說,新人不是應該有個導師嗎,導師得review新人的代碼啊。首先,導師得懂這一塊業務;其次,導師得願意花時間指導新人。指導新人是否影響導師的KPI呢?帶好了是否有獎,出問題了是否有懲?如果全憑導師自律,這個不確定性就太大了。

上面提到的是新人,其實老手也可能寫出“德不配位”的代碼,比如一個需求,可能涉及到多個模塊,有的模塊是這個老手負責的,有的則不是。理想的情況下,各個模塊提供好接口供老手調用即可,但某個模塊的負責人很忙,沒有時間,這個時候老手就會直接去修改相應模塊。可是,可能由於老手特有的自尊、或者面子,老手往往不願意去請教對應模塊的負責人,而是按照自己的經驗魔改出一段可以工作,但既不優雅、也不高效的代碼。

代碼如何加速腐爛

所以說,由於進度壓力、經驗、態度等各種各樣的原因,代碼中慢慢就會開始出現腐朽的問題。可怕的是,垃圾的代碼給出了錯誤的示範,這種示範對於新手或者對於這個模塊不熟悉的同事來說都很強烈,也使得垃圾的代碼、倍增的維護成本、潛在的bug被到處複製,美其名曰“借鑒”。破窗效應,讓後來人寫出垃圾代碼的時候毫無心理負擔,“以前就是這個樣子的”,以前這裡有個變量叫temp,我只是加了個變量叫temp1;以前這裏就有switch case,我只不過加了一個case;以前的代碼就很難讀懂了,於是我copy的一份實現自己的邏輯。

況且,到項目後期,可能不再那麼掙錢了,可能最初寫代碼、制定規範的人已經不再了,誰還會來關心這代碼質量呢?

悲觀的認為,代碼的腐化是必要,只是時間快慢問題。

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

【其他文章推薦】

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

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

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

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

新北清潔公司,居家、辦公、裝潢細清專業服務

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

一個非侵入的Go事務管理庫——如何使用

在文章”清晰架構(Clean Architecture)的Go微服務: 事物管理”中,我談到了如何在清晰架構中實現非侵入的事務管理。

它允許你把事務代碼與業務邏輯代碼分開,並且讓你在編寫業務邏輯時不必考慮事務。但它也有一些缺點。首先,它是整個清晰框架(Clean Architecture)的一部分,所以你不能拋開框架單獨使用它。其次,儘管它對業務邏輯沒有侵入,但它對框架有侵入。你需要修改框架的各個層,使其工作,這使他看起來比較複雜。 第三,正如我在文章中提到的,它存在一個依賴泄漏的漏洞。我雖然在文章中指出了解決方案,但它是一個比較大的改動,因此我當時就把它先放下了。現在,我終於有時間重新拾起它,並做了重要改進,結果令人非常滿意。

項目需求

以下是新的項目需求:

  1. 把事務管理代碼寫成一個單獨的第三方庫,這樣人們就可以在任何框架中使用它。
  2. 使其對框架無侵入,這意味着除了在用例層之外,在清晰架構的任何層中都沒有事務代碼。幾乎所有的事務代碼都在第三方的事務庫中。
  3. 修復以前設計中的依賴泄漏。

最終,我完成了所有的目標,結果出乎意料的好。我將寫兩篇文章來描述它,這篇文章討論如何使用這個第三方庫,下一篇文章討論事務管理庫的工作原理。當你要在應用程序里使用事務管理庫時,你的程序分成了兩部分。一部分是第三方庫的程序,另一部分是應用程序的代碼(它需要調用事務管理庫中的函數)。本文只講應用程序代碼。

如何在項目中使用事務管理庫

要想讓業務函數支持事務,需要做兩件事。首先,創建數據庫鏈接;其次,使用創建的數據庫鏈接運行SQL語句。我假設你在項目中使用了清晰架構。在這種情況下,“創建數據庫鏈接”會在應用程序容器((詳情參見”清晰架構(Clean Architecture)的Go微服務: 程序容器(Application Container)” )中完成,“運行SQL語句”會在業務邏輯(數據持久層)中完成。如果沒有使用清晰架構,你可能會使用某種非常類似的分層架構,結構還是一樣。如果你沒有使用任何框架或分層架構,那麼這兩種代碼可能會在一個地方。

你可能想知道它與沒有事務支持的代碼有什麼不同?幾乎沒有。不管有沒有事務支持,應用程序都要編寫相同的代碼,事務管理庫會在後端處理所有事情。

本文中的所有代碼都在”jfeng45/servicetmpl1″中,這是一個能自我進化的微服務框架,它提供了如何使用事務庫的例子。

創建數據庫鏈接

創建數據庫鏈接有兩種不同的方法,使用哪種方法取決於是否需要緩存數據庫鏈接。

獲取數據庫鏈接

下面是創建數據庫鏈接的代碼。它在”sqlFactory.go”文件中。因為清晰架構使用了工廠方法模式(factory method pattern),這裏的代碼是它的一部分。如果你不想使用工廠方法模式,也是一點問題都沒有的。因為數據庫鏈接在架構中是要被緩存的,所以框架代碼需要調用事務庫中的函數“BuildSqlDB()”,它首先檢查數據庫鏈接是否已經存在。如果沒有,則調用“factory.BuildSqlDB(&tdbc)”來創建一個。在此之前,它獲取需要的參數並將它們保存在“DatabaseConfig”中,“DatabaseConfig”也是在事務庫中定義的。之後它調用內部函數“buildGdbc()”生成合適的“gdbc.SqlGdbc”接口(要根據你是否需要事務)。最後,檢查如果數據庫鏈接不在緩存中,則把它放入緩存。

// implement Build method for SQL database
func (sf *sqlFactory) Build(c container.Container, dsc *config.DataStoreConfig) (DataStoreInterface, error) {
	logger.Log.Debug("sqlFactory")
	key := dsc.Code
	//if it is already in container, return
	if value, found := c.Get(key); found {
		logger.Log.Debug("found db in container for key:", key)
		sdb := value.(*sql.DB)
		return buildGdbc(sdb, dsc.Tx)
	}
	tdbc :=databaseConfig.DatabaseConfig{dsc.DriverName, dsc.UrlAddress, dsc.Tx}
	db, err := factory.BuildSqlDB(&tdbc)
	if err != nil {
		return nil, err
	}
	gdbc, err := buildGdbc(db, dsc.Tx)
	if err != nil {
		return nil, err
	}
	c.Put(key, gdbc)
	return gdbc, nil

}

下面是創建“SqlGdbc”接口的內部函數。”SqlGdbc”接口有兩種實現,一種是”SqlConnTx”,它支持事務。另一個是“SqlDBTx”,它不支持事務。

func buildGdbc(sdb *sql.DB,tx bool) (gdbc.SqlGdbc, error){
	var sdt gdbc.SqlGdbc
	if tx {
		tx, err := sdb.Begin()
		if err != nil {
			return nil, err
		}
		sdt = &gdbc.SqlConnTx{DB: tx}
		logger.Log.Debug("buildGdbc(), create TX:")
	} else {
		sdt = &gdbc.SqlDBTx{sdb}
		logger.Log.Debug("buildGdbc(), create DB:")
	}
	return sdt, nil
}

有一種更簡單的方法可以直接從事務庫中獲得”SqlGdbc”,函數是”factory.Build()”。但是當使用它時,你不能緩存數據庫鏈接,所以我沒有在框架中使用它。但是如果你不需要緩存數據庫鏈接,調用“factory.Build()”是一個更好的方法。

數據庫配置參數

數據庫配置參數是在第三方事務庫中定義的,但數據本身是保存在業務項目中。應用程序首先需要組裝參數並將它們傳遞給事務庫,以便得到合適的數據庫鏈接。在我們的框架中,包括數據庫參數在內的所有應用程序配置數據都保存在一個文件中。框架代碼將負責從文件中獲取數據。你如果不想將參數保存在文件中,直接將參數寫成程序中的硬編碼傳遞給事務庫更容易。

下面是配置文件“appConfigDev.yaml”中的部分代碼。對於數據庫來說,關鍵是如何讓事務庫知道需要的是事務鏈接還是非事務鏈接。它有多種辦法可以完成。例如,你可以為每個函數設置一個事務標誌,但這需要改動大量的代碼。我發現最簡單的方法是將所有支持事務的函數放在一個特殊的用例(Use Case)中。在下面的示例中,有三個用例:“registration”、“listUser”和“registrationTx”,其中只有“registrationTx”是支持事務的,因為它使用“*sqlConfigTx”作為“dataStoreConfig”。

useCaseConfig:
    registration:
        code: registration
        userDataConfig: &userDataConfig
            code: userData
            dataStoreConfig: *sqlConfig
    listUser:
        code: listUser
        userDataConfig: *userDataConfig
        cacheDataConfig: &cacheDataConfig
            code: cacheData
            dataStoreConfig: *cacheGrpcConfig
    registrationTx:
        code: registrationTx
        userDataConfig: &userDataConfigTx
            code: userData
            dataStoreConfig: *sqlConfigTx

下面是來自同一配置文件的部分代碼。可以看到,在“sqlConfigTx”中,有一個參數“tx:ture”,它表明它是支持事務的。

sqlConfig: &sqlConfig
    code: sqldb
    driverName: mysql
    urlAddress: "root:@tcp(localhost:4333)/service_config?charset=utf8"
    dbName:
    tx:  false
sqlConfigTx: &sqlConfigTx
    code: sqldb
    driverName: mysql
    urlAddress: "root:@tcp(localhost:4333)/service_config?charset=utf8"
    dbName:
    tx: true

在業務邏輯中訪問數據庫

我們用一個業務函數做例子,來展示支持事務和不支持事務的兩種不同實現方式,這樣你就能看到他們的區別。

不支持事務的代碼

下面是“ModifyAndUnregister(user *model.User)”的非事務函數, 它在“registration.go”文件中。它是對業務函數“ModifyAndUnregister(ruc.UserDataInterface, user)”的一個簡單封裝,這個業務函數是被事務和非事務代碼共享的。

// The use case of ModifyAndUnregister without transaction
func (ruc *RegistrationUseCase) ModifyAndUnregister(user *model.User) error {
	return ModifyAndUnregister(ruc.UserDataInterface, user)
}

下面是共享的業務函數”ModifyAndUnregister(ruc.UserDataInterface, user)”的代碼,所有的業務邏輯都在這個函數里。

func ModifyAndUnregister(udi dataservice.UserDataInterface, user *model.User) error {
	//loggera.Log.Debug("ModifyAndUnregister")
	err := modifyUser(udi, user)
	if err != nil {
		return errors.Wrap(err, "")
	}
	err = unregisterUser(udi, user.Name)
	if err != nil {
		return errors.Wrap(err, "")
	}
	return nil
}
支持事務的代碼

下面是相同的業務函數,但支持事務的代碼。它在“registrationTx.go”文件中。你要做全部工作就是在“EnableTx()”中調用業務函數。

// The use case of ModifyAndUnregister with transaction
func (rtuc *RegistrationTxUseCase) ModifyAndUnregisterWithTx(user *model.User) error {

	udi := rtuc.UserDataInterface
	return udi.EnableTx(func() error {
		// wrap the business function inside the TxEnd function
		return ModifyAndUnregister(udi, user)
	})
}

下面是函數“EnableTx()”的實現代碼(它在文件“userDataSql.go”中)。 這個代碼是在持久層中。它的實現非常簡單,只需調用事務庫中的函數“TxEnd()”。

func (uds *UserDataSql) EnableTx(txFunc func() error) error {
	return uds.DB.TxEnd(txFunc)
}

以上就是為業務函數添加事務支持所需要做的全部工作,其餘代碼均在事務庫中。

如果你想了解更多關於事務庫本身的信息,請閱讀“一個非侵入的Go事務管理庫——工作原理”,

結論:

我對去年寫的事務管理代碼進行了升級,使其成為一個非侵入式的輕量級事務管理庫。當你使用它時,只需要在應用程序中額外增加兩三行代碼就能搞定,所有其他代碼都放在了事務管理庫。它很好地將業務代碼與數據庫事務代碼隔離開來,這樣你的業務代碼里就只有純粹的業務邏輯。它是一個庫而不是框架,所以不論你使用任何框架都可以使用它。

源代碼:

完整的源碼: “jfeng45/servicetmpl1”

索引:

1 “清晰架構(Clean Architecture)的Go微服務: 事物管理”

2 “清晰架構(Clean Architecture)的Go微服務: 程序容器(Application Container)”

3 “一個非侵入的Go事務管理庫——工作原理”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

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

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

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

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

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

日產汽車2015年將生產首款中國品牌電動汽車

日產汽車高管日前表示,公司到2015年將通過其中國品牌開始生產首款Venucia e30。

公司2013年還將在中國15座城市與當地政府聯合啟動試驗項目,以推廣Venucia e30。日產目前正在武漢和廣州推廣自己品牌的電動汽車Leaf。

日產在中國有多家生產廠房,並計畫2014年在大連再新增1處,但受日本“國有化”釣魚島鬧劇影響,日產在中國的銷售大幅衰退。其10月在華銷售新車6.43萬輛,同比下滑40.7%,降幅較9月的35%進一步擴大。

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

【其他文章推薦】

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

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

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

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

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

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