GraphicsLab Project 之 Screen Space Planar Reflection

作者:i_dovelemon

日期:2020-06-23

主題:Screen Space Planar Reflection, Compute Shader

引言

        前段時間,同事發來一篇講述特化版本的 Screen Space Reflection 實現 Planar Reflection 的文章。出於好奇,實驗了下,看看效果如何。如下是目前實現出來的基礎版本的效果:

 原理

        對於上圖來說, Water Plane 表示水面,上半部分為實際場景的山體,下半部分為以水面為鏡像進行反射之後的山體效果。

        對於山體上某一個點(圖中白色點)來說,它對應的鏡像點為黃色點。

        我們可以從 Screen Position 以及 Depth Texture 信息,計算出來白點的世界坐標位置 WorldPosition

        然後可以以 Water Plane 所在的平面對該 WorldPosition 作鏡像操作,得到 ReflectionPosition

        得到 ReflectionPosition 之後,我們就能夠計算出來 ReflectionPostion 所對應的屏幕坐標 Reflection Screen Position

        根據前面的操作,我們就可以知道,此時 Reflection Screen Position 所反射的顏色即為 Screen Positon 所表示的顏色。

        基礎原理十分簡單,但是實際實現的時候,會發現有很多問題。接下里一一講述。

問題

閃爍

        根據上面的原理,可以想到,有多個像素可能會被反射到相同的位置,如下圖所示:

         這樣由於 GPU 執行順序的不確定性,就會導致畫面出現閃爍,如下所示:

        針對這樣的問題,我們實際需要的反射點是最近的反射點。可以考慮使用 HLSL 中提供的 InterlockedMin/InterlockedMax (參考[1],[2]) 之類的指令,在寫入數據時進行大小比較,從而實現保存最近反射點的功能。

        前面的指令雖然能夠實現大小比較,以此進行排序。但是根據前面的描述,我們實際保存的是反射點的顏色。沒有辦法只根據顏色進行排序,所以我們需要保存其他便於排序的信息,這裏選擇使用反射點的 Screen Position。並且按照如下方式進行編碼,從而實現獲取最近反射點的效果:

                        uint2 SrcPosPixel = uint2(DepthPos.x, DepthPos.y);
                        uint2 ReflPosPixel = ReflPosUV * uint2(ReflectWidth, ReflectHeight);

                        int Hash = SrcPosPixel.y << 16 | SrcPosPixel.x;
                        int dotCare = 0;
                        InterlockedMin(HashResult[ReflPosPixel], Hash, dotCare);

Encode and Sort

孔洞

        根據先前算法的描述,我們知道,我們先要根據 Depth 信息和 Screen Position 信息計算出 World Positon,然後鏡像之後,在轉化為新的屏幕坐標。在這一系列操作中,由於數值計算的不精確性,導致有些地方沒有存儲到有效的反射點位置信息,從而導致最終显示時畫面上有孔洞的情況,如下圖所示:

        幸運的是,從結果看這些孔洞並不會聚集在一起,形成大塊的黑塊。對於這種情況,我們只要在生成反射貼圖的時候,檢測到沒有保存有效位置信息時,遍歷下周圍的像素,尋找到一個擁有有效像素的值即可解決這個問題,如下代碼所示:

        uint Hash = HashTexture[id.xy].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x, id.y + 1)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x, id.y - 1)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x + 1, id.y)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x - 1, id.y)].x;

        if (Hash != 0x0FFFFFFF)
        {
            uint x = Hash & 0xFFFF;
            uint y = Hash >> 16;
            ReflectionTexture[id.xy] = ColorTexture[uint2(x, y)];
        }
        else
        {
            ReflectionTexture[id.xy] = float4(0.0f, 0.0f, 0.0f, 0.0f);
        }

Hole

        如下是修正孔洞之後的效果:

實現

        本文的代碼是使用 Unity 實現的,實現起來比較簡單。比較坑的地方在於 Unity 裏面獲取 Projection Matrix 要通過 GL.GetGPUProjectionMatrix (文獻[3]) 轉化一下才能變成傳遞到 GPU 上用於渲染的投影矩陣。如下是功能核心的 Compute Shader 代碼:

// Each #kernel tells which function to compile; you can have many kernels
#pragma enable_d3d11_debug_symbols
#pragma kernel SSPRClear_Main
#pragma kernel SSPRHash_Main
#pragma kernel SSPRResolve_Main

//-----------------------------------------------------------------
float4x4 VPMatrix;
float4x4 InvVPMatrix;
uint Width;
uint Height;
uint ReflectWidth;
uint ReflectHeight;

//--------------------------------------------------------------------
RWTexture2D<int> ClearHashTexture;

[numthreads(8, 8, 1)]
void SSPRClear_Main(uint3 id : SV_DispatchThreadID)
{
    if (id.x < ReflectWidth && id.y < ReflectHeight)
    {
        ClearHashTexture[id.xy] = 0x0FFFFFFF;
    }
}

//---------------------------------------------------------------
Texture2D<float> DepthTex;
RWTexture2D<int> HashResult;

#define DownSampleFactor (1)

float3 Unproject(float3 clip)
{
    float4 clipW = float4(clip, 1.0f);
    clipW = mul(InvVPMatrix, clipW);
    clipW.xyz = clipW.xyz / clipW.w;
    return clipW.xyz;
}

float2 Project(float3 world)
{
    float4 worldW = float4(world, 1.0f);
    worldW = mul(VPMatrix, worldW);
    worldW.xy = worldW.xy / worldW.w;
    worldW.xy = (worldW.xy + float2(1.0f, 1.0f)) / 2.0f;
    return worldW.xy;
}

[numthreads(8, 8, 1)]
void SSPRHash_Main(uint3 id : SV_DispatchThreadID)
{
    for (uint i = 0; i < DownSampleFactor; i++)
    {
        for (uint j = 0; j < DownSampleFactor; j++)
        {
            uint2 DepthPos = uint2(id.x * DownSampleFactor + i, id.y * DownSampleFactor + j);
            if (DepthPos.x < Width && DepthPos.y < Height)
            {
                float depth = DepthTex.Load(int3(DepthPos.x, DepthPos.y, 0)).x;

                if (depth > 0.0f)
                {
                    float2 uv = (DepthPos.xy * 1.0f) / float2(Width, Height);
                    uv = uv * 2.0f - float2(1.0f, 1.0f);
                    uv.y = -uv.y;

                    float3 PosWS = Unproject(float3(uv, depth));

                    if (PosWS.y > 0.0f)
                    {
                        float3 ReflPosWS = float3(PosWS.x, -PosWS.y, PosWS.z);
                        float2 ReflPosUV = Project(ReflPosWS);

                        uint2 SrcPosPixel = uint2(DepthPos.x, DepthPos.y);
                        uint2 ReflPosPixel = ReflPosUV * uint2(ReflectWidth, ReflectHeight);

                        int Hash = SrcPosPixel.y << 16 | SrcPosPixel.x;
                        int dotCare = 0;
                        InterlockedMin(HashResult[ReflPosPixel], Hash, dotCare);
                    }
                }
            }
        }
    }
}

//------------------------------------------------------------------------------
Texture2D<int> HashTexture;
Texture2D<float4> ColorTexture;
RWTexture2D<float4> ReflectionTexture;

[numthreads(8, 8, 1)]
void SSPRResolve_Main(uint3 id : SV_DispatchThreadID)
{
    if (id.x < ReflectWidth && id.y < ReflectHeight)
    {
        uint Hash = HashTexture[id.xy].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x, id.y + 1)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x, id.y - 1)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x + 1, id.y)].x;
        if (Hash == 0x0FFFFFFF)
            Hash = HashTexture[uint2(id.x - 1, id.y)].x;

        if (Hash != 0x0FFFFFFF)
        {
            uint x = Hash & 0xFFFF;
            uint y = Hash >> 16;
            ReflectionTexture[id.xy] = ColorTexture[uint2(x, y)];
        }
        else
        {
            ReflectionTexture[id.xy] = float4(0.0f, 0.0f, 0.0f, 0.0f);
        }
    }
}

ScreenSpacePlanarReflection

結論

        本文只是探索這個方法的可能性,更加複雜的實現,更加高效的優化可以參考文獻[4][5],這也是本文主要參考的對象。

        相比於傳統的繪製場景兩邊的方法來說,這個方案的性能更加高效,同時也沒有 SSR 那樣的高需求。在條件滿足的情況下,使用該方案能夠帶來顯著的效果提升,推薦可以嘗試。

        完整代碼在這裏:https://github.com/idovelemon/UnityProj/tree/master/ScreenSpacePlanarReflection

參考文獻

[1] HLSL-InterlockedMax

[2] HLSL-InterlockedMin

[3] GL.GetGPUProjectionMatrix

[4] Screen Space Planar Reflection

[5] Optimized Pixel Projected Reflections for Planar Reflectors

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

【其他文章推薦】

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

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

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

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

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

歐洲各國豪雨不斷 洪水土石流頻傳

摘錄自2019年11月27日公視報導

美澳野火肆虐,在歐洲則是飽受洪災侵襲,包括義大利、法國和希臘,當地從上個週末以來就豪雨不斷;各地接連發生洪水和土石流災情,至少已經傳出有九人死亡。

有的汽車卡在樹上,有的掉進泥池裡,所有東西都被大水沖得四散各地,連路面也跟著崩塌毀損,每戶民宅裡外都是一片狼藉。這是希臘西部這幾天遭受暴雨襲擊過後的景象,面對天災,居民有苦難言。

當地居民說,「水勢洶洶而來,當我們呼叫人在地下室的孩子時,什麼東西都沒有了,門啊、窗啊,洗衣機都在庭院裡了,你去那邊看看庭院的狀況,原本停了五台車,現在一台也不剩。」類似的豪雨災情,同樣出現在義大利北部,靠近山區的一座高架橋不敵洪水與土石流,應聲斷裂、坍塌,所幸目前沒有發現人員傷亡。

另一個為強降雨所苦的地區是法國南部,其中,瓦爾省境內受到洪患影響最大的幾座城鎮,短短48小時之內就累積了三個月的降雨量。許多地方河川潰堤,導致嚴重淹水,而等到星期一部分地區水位退去之後,有4500個住戶停電。

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

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

野豬殺人!美德州婦女遭多頭豬隻襲擊慘死

摘錄自2019年11月26日自由時報報導

美國德州錢伯斯郡阿納瓦克(Anahuac)發生罕見的動物襲擊案,幫忙照料一對老夫妻的59歲看護羅林斯(Christine Rollins)於24日上班時間遲遲沒有現身,84歲的屋主等不下去外出查看時,驚見她陳屍在屋外,目前當局認為她遭到多隻野豬攻擊死亡。

據《CNN》報導,錢伯斯郡警長霍桑(Brian Hawthorne)於25日的新聞發布會指出,羅林斯於24日清晨6時至6時30分左右,遭遇不同野豬的襲擊,當時外面天色還很黑。

霍桑指出,這是他從警35年以來所見過最糟糕的事情之一,法醫里弗斯(Selly Rivers)確認現場有多頭豬隻犯案,因為羅林斯身上的咬傷傷口大小不一。

德州公園和野生動物局的資料顯示,成年野豬的體重在100磅至400磅之間(約45.3公斤至181公斤)。霍桑則透露,野豬的確在德州造成問題,但很少出現襲擊人類的案件。

※ 本文與 行政院農業委員會 林務局   合作刊登

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

【其他文章推薦】

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

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

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

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

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

日本第一例!技術員確診人猴共通「疱疹B病毒感染症」 出現發燒、頭痛症狀

摘錄自2019年11月29日ETtoday綜合報導

日本鹿兒島市28日傳出,「新日本科學」公司鹿兒島市動物實驗設施內,一名技術員被診斷出患有「疱疹B病毒感染症」,是日本境內第一例,而這個相當罕見的病症,在全球僅有約50例確診。

根據台灣衛生福利部疾病管制署網站解釋,疱疹B病毒為人畜共通傳染性病原體,會對感染者的中樞神經系統進行破壞。疱疹B病毒於1932年在美國出現第一例,研究人員B博士(Dr. B)當時被一隻看起來相當健康的恆河猴咬傷,15天後便因急性腦脊髓炎死亡,病毒的名稱也採B博士名字命名為「疱疹B病毒」。疱疹B病毒並無特別季節變化,一年四季的傳染能力同樣活躍。

日本《讀賣新聞》、《中央社》報導,受託開發醫藥品的「新日本科學公司」總社位於東京,並在鹿兒島市設有一處研究設施;一名實驗業務助理在對猴子進行安全性調查時,不慎感染了疱疹B病毒感染症(Herpesvirus B Infection),今年2月出現頭痛、發燒等症狀,但直到8月底轉願接受基因檢查,才在11月上旬被驗出確診。

這類流行於獼猴、日本獼猴等獼猴屬猿猴間的病毒不會經由空氣傳染,主要透過抓、咬受傷後進入人體,潛伏期約2至5週,發病會出現發燒、麻痺等症狀。

鹿兒島市和新日本科學公司並未對外公布實驗業務助理的姓名,也未透露身體狀況、性別和年齡。報導指出,該名技術員平常直接接觸猿猴的機會很少,就診時也沒有被猿猴抓、咬的痕跡,目前正進一步調查染病途徑。

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

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

野火過後恐現泥石流 加州聖巴巴拉發疏散警告

摘錄自2019年11月28日中央通訊社綜合報導

暴雨今天(27日)襲擊洛杉磯北部地區,讓與野火奮鬥的救災人員得以舒緩,但也帶來新的泥石流危險,迫使當局向17.5平方公里地區內的居民發布疏散警告。

「華爾街日報」(Wall Street Journal)報導,根據與消防員合作的氣象學家,190毫米的大雨凌晨1時開始襲擊加州聖巴巴拉(Santa Barbara),預料將降下更多雨勢。

因可能發生泥石流,聖巴巴拉郡警察局向凱夫大火(Cave Fire)及太平洋中間17.5平方公里內的居民發布疏散警告。泥石流可能發生在大雨過後、泥沙土石鬆軟的野火區域,並以危險的速度向下滑。

當局表示,本週到今天下午沒有發生泥石流,但威脅可能持續整個冬天,直到灌木叢重新開始在火災過後的地區生長。

聖巴巴拉郡消防局的蓋里(Tim Gailey)警告消防員,在路上保持警惕,特別是許多火災撤離者今天獲准返家時。他在大雨中表示:「會產生逕流、泥濘、砂石與樹木之類的東西,一起流到路上。」

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

【其他文章推薦】

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

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

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

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

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

沒想到,這麼簡單的線程池用法,深藏這麼多坑!

又又又踩坑了

生產有個對賬系統,每天需要從渠道端下載對賬文件,然後開始日終對賬。這個系統已經運行了很久,前两天突然收到短信預警,沒有獲取渠道端對賬文件。

ps:對賬系統詳細實現方式:對賬系統設計與實現

本以為又是渠道端搞事情,上去一排查才發現,所有下載任務都被阻塞了。再進一步排查源碼,才發現自己一直用錯了線程池某個方法。

由於線程創建比較昂貴,正式項目中我們都會使用線程池執行異步任務。線程池,使用池化技術保存線程對象,使用的時候直接取出來,用完歸還以便使用。

雖然線程池的使用非常方法非常簡單,但是越簡單,越容易踩坑。細數一下,這些年來因為線程池導致生產事故也有好幾起。

所以今天,小黑哥就針對線程池的話題,給大家演示一下怎麼使用線程池才會踩坑。

希望大家看完,可以完美避開這些坑~

先贊后看,養成習慣。微信搜索「程序通事」,關注就完事了!

慎用 Executors 組件

Java 從 JDK1.5 開始提供線程池的實現類,我們只需要在構造函數內傳入相關參數,就可以創建一個線程池。

不過線程池的構造函數可以說非常複雜,就算最簡單的那個構造函數,也需要傳入 5 個參數。這對於新手來說,非常不方便哇。

也許 JDK 開發者也考慮到這個問題,所以非常貼心給我們提供一個工具類 Executors,用來快捷創建創建線程池。

雖然這個工具類使用真的非常方便,可以少寫很多代碼,但是小黑哥還是建議生產系統還是老老實實手動創建線程池,慎用Executors,尤其是工具類中兩個方法 Executors#newFixedThreadPoolExecutors#newCachedThreadPool

如果你圖了方便使用上述方法創建了線程池,那就是一顆定時炸彈,說不準那一天生產系統就會。

我們來看兩個,看下這個這兩個方法會有什麼問題。

假設我們有個應用有個批量接口,每次請求將會下載 100w 個文件,這裏我們使用 Executors#newFixedThreadPool批量下載。

下面方法中,我們隨機休眠,模擬真實下載耗時。

為了快速復現問題,調整 JVM 參數為 -Xmx128m -Xms128m

private ExecutorService threadPool = Executors.newFixedThreadPool(10);

/**
 * 批量下載對賬文件
 *
 * @return
 */
@RequestMapping("/batchDownload")
public String batchDownload() {
    
    // 模擬下載 100w 個文件
    for (int i = 0; i < 1000000; i++) {
        threadPool.execute(() -> {
            // 隨機休眠,模擬下載耗時
            Random random = new Random();
            try {
                TimeUnit.SECONDS.sleep(random.nextInt(100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    return "process";
}

程序運行之後,多請求幾次這個批量下載方法,程序很快就會 OOM

查看 Executors#newFixedThreadPool源碼,我們可以看到這個方法創建了一個默認的 LinkedBlockingQueue 當做任務隊列。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

這個問題槽點就在於 LinkedBlockingQueue,這個隊列的默認構造方法如下:

/**
 * Creates a {@code LinkedBlockingQueue} with a capacity of
 * {@link Integer#MAX_VALUE}.
 */
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

創建 LinkedBlockingQueue 隊列時,如果我們不指定隊列數量,默認數量上限為 Integer.MAX_VALUE。這麼大的數量,我們簡直可以當做無界隊列了。

上面我們使用 newFixedThreadPool,我們僅使用了固定數量的線程下載。如果線程都在執行任務,線程池將會任務加入任務隊列中。

如果線程池執行任務過慢,任務將會一直堆積在隊列中。由於我們隊列可以認為是無界的,可以無限制添加任務,這就導致內存佔用越來越高,直到 OOM 爆倉。

ps:線程池基本工作原理

下面我們將上面的例子稍微修改一下,使用 newCachedThreadPool 創建線程池。

程序運行之後,多請求幾次這個批量下載方法,程序很快就會 OOM ,不過這次報錯信息與之前信息與之前不同。

從報錯信息來看,這次 OOM 的主要原因是因為無法再創建新的線程。

這次看下一下 newCachedThreadPool 方法的源碼,可以看到這個方法將會創建最大線程數為 Integer.MAX_VALUE 的的線程池。

由於這個線程池使用 SynchronousQueue 隊列,這個隊列比較特殊,沒辦法存儲任務。所以默認情況下,線程池只要接到一個任務,就會創建一個線程。

一旦線程池收到大量任務,就會創建大量線程。Java 中的線程是會佔用一定的內存空間 ,所以創建大量的線程是必然會導致 OOM

先贊后看,養成習慣。微信搜索「程序通事」,關注就完事了!

復用線程池

由於線程池的構造方法比較複雜,而 Executors 創建的線程池比較坑,所以我們有個項目中自己封裝了一個線程池工具類。

工具類代碼如下:

public static ThreadPoolExecutor getThreadPool() {
    // 為了快速復現問題,故將線程池 核心線程數與最大線程數設置為 100
    return new ThreadPoolExecutor(100, 100, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(200));
}

項目代碼中這樣使用這個工具類:

@RequestMapping("/batchDownload")
public String batchDownload() {
    ExecutorService threadPool = ThreadPoolUtils.getThreadPool();

    // 模擬下載 100w 個文件
    for (int i = 0; i < 100; i++) {
        threadPool.execute(() -> {
            // 隨機休眠,模擬下載耗時
            Random random = new Random();
            try {
                TimeUnit.SECONDS.sleep(random.nextInt(100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }

    return "process";
}

使用 WRK 工具對這個接口同時發起多個請求,很快應用就會拋出 OOM

每次請求都會創建一個新的線程池執行任務,如果短時間內有大量的請求,就會創建很多的線程池,間接導致創建很多線程。從而導致內存佔盡,發生 OOM 問題。

這個問題修復辦法很簡單,要麼工具類生成一個單例線程池,要麼項目代碼中復用創建出來的線程池。

Spring 異步任務

上面代碼中我們都是自己創建一個線程池執行異步任務,這樣還是比較麻煩。在 Spring 中, 我們可以在方法上使用 Spring 註解 @Async,然後執行異步任務。

代碼如下:

@Async
public void async() throws InterruptedException {
    log.info("async process");
    Random random = new Random();
    TimeUnit.SECONDS.sleep(random.nextInt(100));
}

不過使用 Spring 異步任務,我們需要自定義線程池,不然大量請求下,還是有可能發生 OOM 問題。

這是原因主要是 Spring 異步任務默認使用 Spring 內部線程池 SimpleAsyncTaskExecutor

這個線程池比較坑爹,不會復用線程。也就是說來一個請求,將會新建一個線程。

所以如果需要使用異步任務,一定要使用自定義線程池替換默認線程池。

如果使用 XML 配置,我們可以增加如下配置:

<task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>

如果使用註解配置,我們需要設置一個 Bean:

@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(10);
    executor.setThreadNamePrefix("test-%d");
    // 其他設置
    return new ThreadPoolTaskExecutor();
}

然後使用註解時指定線程池名稱:

@Async("threadPoolTaskExecutor")
public void xx() {
    // 業務邏輯
}

如果是 SpringBoot 項目,從本人測試情況來看,默認將會創建核心線程數為 8,最大線程數為 Integer.MAX_VALUE,隊列數也為 Integer.MAX_VALUE線程池。

ps:以下代碼基於 Spring-Boot 2.1.6-RELEASE,暫不確定 Spring-Boot 1.x 版本是否也是這種策略,熟悉的同學的,也可以留言指出一下。

雖然上面的線程池不用擔心創建過多線程的問題,不是還是有可能隊列任務過多,導致 OOM 的問題。所以還是建議使用自定義線程池嗎,或者在配置文件修改默認配置,例如:

spring.task.execution.pool.core-size=10
spring.task.execution.pool.max-size=20
spring.task.execution.pool.queue-capacity=200

Spring 相關踩坑案例: Spring 定時任務突然不執行

線程池方法使用不當

最後再來說下文章開頭的我踩到的這個坑,這個問題主要是因為理解錯這個方法。

錯誤代碼如下:

// 創建線程池
ExecutorService threadPool = ...
List<Callable<String>> tasks = new ArrayList<>();
// 批量創建任務
for (int i = 0; i < 100; i++) {
    tasks.add(() -> {
        Random random = new Random();
        try {
            TimeUnit.SECONDS.sleep(random.nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "success";
    });
}
// 執行所有任務
List<Future<String>> futures = threadPool.invokeAll(tasks);
// 獲取結果
for (Future<String> future : futures) {
    try {
        future.get();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

上面代碼中,使用 invokeAll執行所有任務。由於這個方法返回值為 List<Future<T>>,我誤以為這個方法如 submit一樣,異步執行,不會阻塞主線程。

實際上從源碼上,這個方法實際上逐個調用 Future#get獲取任務結果,而這個方法會同步阻塞主線程。

一旦某個任務被永久阻塞,比如 Socket 網絡連接位置超時時間,導致任務一直阻塞在網絡連接,間接導致這個方法一直被阻塞,從而影響後續方法執行。

如果需要使用 invokeAll 方法,最好使用其另外一個重載方法,設置超時時間。

總結

今天文章通過幾個例子,給大家展示了一下線程池使用過程一些坑。為了快速復現問題,上面的示例代碼還是比較極端,實際中可能並不會這麼用。

不過即使這樣,我們千萬不要抱着僥倖的心理,認為這些任務很快就會執行結束。我們在生產上碰到好幾次事故,正常的情況執行都很快。但是偶爾外部程序抽瘋,返回時間變長,就可能導致系統中存在大量任務,導致 OOM

最後總結一下幾個線程池幾個最佳實踐:

第一,生產系統慎用 Executors 類提供的便捷方法,我們需要自己根據自己的業務場景,配置合理的線程數,任務隊列,拒絕策略,線程回收策略等等,並且一定記得自定義線程池的命名方式,以便於後期排查問題。

第二,線程池不要重複創建,每次都創建一個線程池可能比不用線程池還要糟糕。如果使用其他同學創建的線程池工具類,最好還是看一下實現方式,防止自己誤用。

第三,一定不要按照自己的片面理解去使用 API 方法,如果把握不準,一定要去看下方法上註釋以及相關源碼。

歡迎關注我的公眾號:程序通事,獲得日常乾貨推送。如果您對我的專題內容感興趣,也可以關注我的博客:studyidea.cn

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

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

用戶畫像產品化——從零開始搭建實時用戶畫像(六)

在開發好用戶標籤以後,如何將標籤應用到實際其實是一個很重要的問題。只有做好產品的設計才能讓標籤發揮真正的價值,本文將介紹用戶畫像的產品化過程。

一、標籤展示

首先是標籤展示功能,這個主要供業務人員和研發人員使用,是為了更直觀的看見整個的用戶標籤體系。

不同的標籤體系會有不同的層級,那麼這個頁面的設計就需要我們展示成樹狀的結構,方便以後的擴展。

在最後一個層級,比如自然性別,可以設計一個統計頁面,在進入頁面后,可以展示相應的數據統計情況,

可以更直觀看見標籤中值得比例,也可以為業務提供好的建議,另外可以對標籤的具體描述進行展示,起到一個說明的作用,還可以展示標籤按天的波動情況,觀察標籤的變化情況。

這一部分的數據來源呢?之前也提到過,這些標籤的元數據信息都存在mysql中,方便我們查詢。

所以樹狀圖和標籤描述信息需要去mysql中獲取,而比例等圖表數據則是從Hbase,Hive中查詢獲取的,當然也有直接通過ES獲取的。但是每天的標籤歷史波動情況,還是要通過每天跑完標籤后存在mysql中作為歷史記錄進行展示。

二 、標籤查詢

這一功能可以提供給研發人員和業務人員使用。

標籤查詢功能其實就是對用戶進行全局畫像的過程,對於一個用戶的全量標籤信息,我們是需要對其進行展示的。

輸入用戶id后,可以查看該用戶的屬性信息、行為信息、風控屬性等信息。從多方位了解一個具體的用戶特徵。

這些已經是標籤的具體信息了,由於是對單一id的查找,從hive中獲取會造成查詢速度的問題,所以我們更建議從Hbase或者ES中查詢獲取,這樣查詢效率和實時性都能獲得極大的提升。

三、標籤管理

這一功能是提供給研發人員使用的。

對於標籤,不能每一次新增一個標籤都進行非常大改動,這樣是非常耗費人力的,所以必須要有可以對標籤進行管理的功能。

這裏定義了標籤的基本信息,開發方式,開發人員等等,在完成標籤的開發以後,直接在此頁面對標籤進行錄入,就可以完成標籤的上線工作,讓業務人員可以對標籤進行使用。

新增和編輯標籤的頁面,可以提供下拉框或者輸入框提供信息錄入的功能。

之前已經提到過,這些標籤的元數據信息都保存在了Mysql中,只要完成對其的新增和修改就可以了。

四、用戶分群

作為用戶畫像最核心的功能,用戶分群功能。是用戶畫像與業務系統建立聯繫的橋樑,也是用戶畫像的價值所在。

這項功能主要供業務人員使用。

此功能允許用戶自定義的圈定一部分人員,圈定的規則就是對於標籤的條件約束。

在圈定好人群以後,可以對這部分人群提供與業務系統的外呼系統,客服系統,廣告系統,Push系統的交互,達到真正的精細化運營的目的。

對於標籤規則的判斷,需要將記錄好的規則存儲於Mysql中,在進行人群計算時又需要將規則解析成可計算的邏輯。不管是解析成Sql或者其他的查詢語言都難度巨大,這對於研發是一個非常大的挑戰。

在此功能中,還可以增加人群對比的功能,對不同人群的不同標籤進行圈定,對比。這對於查詢性能也是一個巨大的考驗。

但是,用戶分群功能作為用戶畫像的核心是我們必須要實現的。對於技術架構,Hbase更擅長與KV形式的查詢,對於多維度查詢性能較差,所以可以採取ES索引,在ES查詢出Hbase的Rowkey,再去查詢Hbase的方式。也有很多公司選擇整體遷移到ES中完成此項工作。那麼ES可以勝任這項工作嗎?

下一章,我們來聊一聊如何用ES來實現用戶分群,未完待續~

參考文獻

《用戶畫像:方法論與工程化解決方案》

更多實時數據分析相關博文與科技資訊,歡迎關注 “實時流式計算” 獲取用戶畫像相關資料 請關注 “實時流式計算” 回復 “用戶畫像”

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

【其他文章推薦】

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

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

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

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

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

冰河期大氣中二氧化碳濃度為何比較低? 關鍵證據找到了

編譯:嚴融怡(胡適國小創思組科任教師)

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

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

印度海灘白色毒泡沫 釀新一波污染危機

摘錄自2019年12月02日中央通訊社報導

印度坦米爾那都省(Tamil Nadu)首府清奈(Chennai)著名的馬利納海灘(Marina Beach)今天(2日)連續第4天被白色泡沫覆蓋,造成印度新一波污染危機。

法新社報導,即使泡沫散發出陣陣刺鼻氣味,孩子們仍在海灘上的白色泡沫堆裡玩耍和自拍。漁民則被告知不要前往附近海域。醫生警告,白色泡沫可能引發皮膚問題。這些泡沫形成於每年季風季,但今年的「毒泡沫」危機特別嚴重。

坦米爾那都省污染控制局(Tamil Nadu Pollution Control Board)表示,他們正在分析泡沫樣本。這些泡沫蔓延海灘數公里。清奈印度國家海岸研究中心(National Centre for Coastal Research)科學家米西拉(Pravakar Mishra)指出:「民眾接觸泡沫絕對不好,但他們就是不了解風險。」

根據米西拉的說法,大部分泡沫是由洗滌劑殘留物和其他廢棄物混合而成。

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

【其他文章推薦】

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

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

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

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

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

儲電技術與成本 抑制印度煤電成長的關鍵 | 解讀《 2019年世界能源展望》報告2/3

環境資訊中心外電;姜唯 翻譯;林大利 審校;稿源:Carbon Brief 前言:國際能源署(IEA)11月13日發表2019年《世界能源展望》報告。810頁報告的特點在於「承諾政策情境」(Stated Policies Scenario, STEPS),反映政府已經說出口的政策的效果──風能和太陽能的激增將使再生能源滿足全球能源需求的大部分成長。但是煤炭的平穩發展,加上對石油和天然氣的需求不斷增加,全球排放量在到2040年的展望期內將繼續上升。 相對地,報告的「永續發展情境」(Sustainable Development Scenario, SDS)描繪出有50%機率將升溫限制在1.65°C內所需的條件,IEA表示這是「完全符合巴黎協定」的情況──SDS需要投資「大量重新分配」,從化石燃料轉向效率和再生能源、淘汰全球約一半的燃煤電廠,以及全球經濟的其他變化。

二氧化碳排放量

()在STEPS之下,全球來自能源的碳排放量將在2018年創紀錄後繼續上升,本世紀很可能升溫2.7°C以上。 下表中的黑色虛線表示此排放軌跡。

相反地,SDS(紅色粗線)之下碳排迅速下降,比2010年還下降17%,2040年下降48%,2050年下降68%。IEA說,如此可在2070年實現淨零排放,並且有50%的機會將升溫限制在1.65°C,或66%的機會停在1.8°C。

這條軌跡的積極度比大多數1.5°C途徑要低,升溫沒有或是僅一小段時間超標(下圖中的黃線)。 政府間氣候變遷專門委員會(IPCC)在其1.5°C特別報告中表示,1.5°C途徑需要在2030年將碳排降至2010年水平的45%,並在2050年達到淨零。

過去(實線)和未來各種不同情境下,來自能源和工業的全球二氧化碳排放量:IEA STEPS(黑色虛線)、IEA SDS(粗紅線)、IPCC升溫1.5℃內途徑,沒有或有限的升溫度超標(細黃線)、IPCC升溫超過1.5C途徑(藍色)以及IPCC升溫2C途徑(灰色)。低於零的值表示負排放,即來自能源和工業的二氧化碳增加量少於移除量,這裡主要是指有碳捕獲和儲存(BECCS)的生物能。資料來源:國際能源署《 2019年世界能源展望》和Carbon Brief對IPCC 1.5℃暖化特別報告的簡要分析。圖片由Carbon Brief用Highcharts繪製。

根據IEA資料,SDS「使全球氣溫上升控制在遠低於2°C……並力求控制在1.5°C以內,完全符合《巴黎協定》目標」。還提供了兩種表現可以超越SDS,同時升溫保持在1.5°C以下的選擇。

「力求」不一定是實現目標,而是朝著目標前進,或者是非常接近1.5°C-只要有額外的行動。

除了WEO中心觀點STEPS外,巴黎協定中所謂的「非常接近」也是飽受非政府組織、科學家、商業團體和其他組織批評的語言。他們今年四月寫信呼籲IEA模擬出有66%機率將升溫限制在1.5°C的情境。

這封信的其中一位作者、倫敦帝國理工學院格蘭瑟姆研究所氣候變遷和環境講師羅傑爾(Joeri Rogelj)博士說,SDS和1.5°C不一致,和《巴黎協定》也有些面向不同。

羅傑爾是IPCC 1.5°C特別報告第二章的協調主要作者,也是IPCC即將發布的第六次評估報告中第一工作組的主要作者。

他告訴Carbon Brief,巴黎協定的「力求1.5°C」至少有兩種可能的解釋,一種是將峰值升溫限制在1.5°C,另一種是可以超過再降回。「把錯過目標納入計畫當中,不能合理解釋成完全符合《巴黎協定》,」羅傑爾說。

他還指出了協定的第4條,致力於在人為碳排放源與所有溫室氣體匯之間達到「平衡」。要實現這個目標可能需要淨負​碳排​,SDS沒有達成這一點的詳細途徑。

負碳排可以透過技術解決方案實現,如帶有碳捕集與封存的生物能源(BECCS),也可透過自然氣候解決方案達成,如綠化。

IEA表示,負排放確實是SDS之下達成1.5°C的一種方法,總共需要清除大約3000億噸的二氧化碳(GtCO2)才能彌補這個差距。然而IEA也承認,大規模部署負碳排設備的永續性和可交付性的確存在隱憂。

WEO說:

考慮到負排放技術的問題,構建一個超越SDS、2050年實現零碳排放,並有50%的機率將升溫限制在1.5°C,而無需依賴淨負碳排的情境是有可能的。

(這個情境已經有人做出,收錄在IPCC的1.5°C報告和上圖中。)

IEA表示,要超越SDS,全世界必須正面對抗那些最困難的領域,如航空、重工業和建築供熱,包括全面性的建築改造、工業過程新技術的開發和改造。

IEA表示,這「不只是擴大SDS中的變革而已」,而是要「面對非常困難且難以克服的挑戰」,有一些領域需要社會大眾的接受度和行為改變:

「這不是能源業內部就能做到的事,而是整個社會的任務……需要跨非常多領域進行大規模變革,這將直接影響幾乎每個人的生活。」

雖然有點挑戰性,但如果IEA能建構出1.5°C情境,政策規劃人員可以參考IEA模型來瞭解各種能源和氣候選擇。隨著各國政府根據《巴黎協定》重新考慮其氣候承諾,並在2020年推出新一輪的國家自主減排計畫,這個參考資料將顯得很重要。

煤炭的變化

報告內有去年版本至今的各種變動,反映相對於基準年的變化-2018年需求增加力道異常強勁-以及新增或修訂的政策。

IEA再次下調了STEPS下的煤炭需求前景,如下圖所示(紅線)。但是煤炭近期前景提高了,部分原因是中國重新依賴高污染產業來支撐增長緩慢。

全球煤炭需求歷史(黑線,百萬噸石油當量)和IEA前一版中心觀點情境的未來成長(藍色色塊)。今年的STEPS以紅色標示,SDS以黃色標示。資料來源:國際能源署《 2019年世界能源展望》和前一版報告。Carbon Brief使用Highcharts繪製。

照STEPS的計畫和政策,儘管近期需求有所增長,今年燃煤用量將會低於2014年的峰值,但仍遠高於SDS之下、暖化遠低於2°C途徑的水準(上圖黃線)。

STEPS之下,美國和歐盟等已開發經濟體煤炭用量快速下降,但印度需求增長是保持全球煤炭用量穩定的關鍵因素之一。

印度這波成長的部分原因是大量新火力發電廠興建中,到2040年將打造出232GW的容量,成長一倍,佔全球新增容量的1/3。

IEA表示,如果電池儲存成本的下降速度快於預期,印度的煤電容量成長將被「大幅削減」。 IEA表示,太陽能和廉價的儲存技術可以「重塑印度電力結構的演變」,並提供「非常引人注目的經濟和環境主張」。

印度的高壓電塔。照片來源: 。

值得注意的另一點是,印度目前燃煤容量只有85GW,IEA預計的新燃煤容量卻高達232GW,其中有1/4已經被凍結多年。

自2010年以來,由於廉價再生能源的競爭、公用事業公司財務困境和公眾的反對,有額外510GW的新煤電廠計畫被取消。

此外,印度政府一再高估了電力需求的增長,現有煤電容量的運行時間不到2/3。2019年至今的數據顯示,印度煤炭發電量可能正在下降。

印度政府最近宣布了一個相當積極的目標,太陽能、風能和生質能的容量要達到450GW,最快2030年達成。IEA的STEPS到2030年僅增加344GW。根據近期Carbon Brief的分析,如果能夠達到這個目標,那麼風能、太陽能和其他低碳能源可以在不增加新煤電的情況下,滿足日益增長的需求。(2/3,未完待續)

‘Profound shifts’ underway in energy system, says IEA World Energy Outlook (2/3) by Simon Evans

CO2 emissions

In the STEPS, global CO2 emissions from energy would continue to rise from the they reached in 2018, putting the world on track for upwards of 2.7C of warming this century. This emissions trajectory is shown with the dashed black line in the chart, below.

In contrast, CO2 declines quickly in the SDS (thick red line) to 17% below 2010 levels by 2030, 48% by 2040 and 68% by 2050. According to the IEA, this is “on course for net-zero emissions by 2070” and corresponds to a 50% likelihood of limiting warming to 1.65C, or a 66% chance of 1.8C.

This trajectory is less ambitious than most pathways to 1.5C with no or limited overshoot (yellow lines, below). In its on 1.5C, the (IPCC) said this would need CO2 to fall 45% below 2010 levels by 2030 and to net-zero by 2050.

Global CO2 emissions from energy and industrial processes in the past (solid black line) and under a range of different scenarios for the future: IEA STEPS (dashed black); IEA SDS (thick red line); IPCC pathways limiting warming to 1.5C this century with no or limited temperature overshoot (thin yellow lines); pathways to 1.5C with high overshoot (blue); and IPCC 2C pathways (grey). Values below zero indicate negative emissions, where residual CO2 from energy and industry is more than offset by removals, here primarily bioenergy with carbon capture and storage (BECCS). Source: IEA and Carbon Brief analysis of the for the IPCC of warming. Chart by Carbon Brief using .

According to the IEA, the SDS charts “a path fully aligned with the by holding the rise in global temperatures to ‘well below 2C…and pursuing efforts to limit [it] to 1.5C’”. It also offers two options for going beyond the SDS to keep warming below 1.5C.

This form of words implies either that “pursue” means to head towards a goal, without necessarily reaching it, or that the SDS is aligned with 1.5C – so long as it is accompanied by additional action.

Along with the WEO’s central focus on the STEPS pathway, the statement on Paris “alignment” is at the heart of from a group of NGOs, scientists, business groups and others. In an , they called for the IEA to develop a scenario with a 66% chance of limiting warming to 1.5C.

One of the letter’s authors, , a lecturer in climate change and the environment at the , says the SDS is “inconsistent with 1.5C and several aspects of the Paris Agreement”.

Rogelj was a coordinating lead author on chapter two of the IPCC and is a for working group one on the IPCC’s forthcoming .

He tells Carbon Brief that there are at least two potential interpretations of the Paris ambition to “pursue efforts towards 1.5C”. One is that of limiting peak warming to 1.5C and the other is overshooting this level before returning below 1.5C, Rogelj says: “Planning to simply miss it is not a reasonable interpretation for a scenario that wants to be fully aligned with the Paris Agreement.”

He also points to of the deal, which commits to reaching a “balance” between human sources and sinks of all greenhouse gases. This goal is likely to require net-negative CO2, for which the SDS provides no detailed pathway.

Negative CO2 emissions could be provided via , such as (BECCS), or using “”, such as afforestation.

The IEA says that negative emissions do indeed offer one way that the SDS could become aligned to a 1.5C limit. A cumulative total of around 300bn tonnes of CO2 (GtCO2) would need to be removed to bridge this gap, it adds. There are over the sustainability and deliverability of such extensive deployment, however, and these are acknowledged by the IEA.

The WEO says:

“[I]t would be possible in the light of concern about [negative emissions technologies] to construct a scenario that goes further than the Sustainable Development Scenario and delivers a 50% chance of limiting warming to 1.5C without any reliance on net-negative emissions on the basis of a zero carbon world by 2050.”

[Other groups have developed a limited of that already do this, which are included in the IPCC’s and the figure above.]

To go beyond its SDS, the IEA says the world would need to tackle “hard to abate” sectors, such as aviation, heavy industry and heat for buildings. This would include near-universal building retrofits and the development and retrofitting of new technologies for industrial processes.

The IEA says this “would not amount to a simple extension” of the changes in the SDS, instead “pos[ing] challenges that would be very difficult and very expensive to surmount.” It adds that tackling some of these areas would require social acceptance and behavioural change:

“This is not something that is within the power of the energy sector alone to deliver. It would be a task for society as a whole…Change on a massive scale would be necessary across a very broad front, and would impinge directly on the lives of almost everyone.”

If the IEA were to develop a 1.5C scenario, despite the challenges it would present, then the agency’s modelling could be used by policymakers to inform their energy and climate choices. Such guidance would be pertinent as governments reconsider their climate pledges under the Paris Agreement, with a fresh round of “” due in 2020.

Coal changes

The outlook includes various changes since last year’s edition, reflecting shifts in the base year – there was growth in demand in 2018 – and new or amended policy.

As a result, the IEA has once again revised down its outlook for coal demand in the central STEPS pathway, as the chart below shows (red line). However, it has also raised its near-term outlook for coal, in part due to China’s renewed industries to prop up flagging growth.

Historical global coal demand (black line, millions of tonnes of oil equivalent) and the IEA’s previous central scenarios for future growth (shades of blue). This year’s STEPS is shown in red and the SDS is in yellow. Source: IEA and previous editions of the outlook. Chart by Carbon Brief using .

Despite the near-term increase in expected demand, this year’s outlook affirms that coal use would remain below the global peak reached in 2014, if stated plans and policies are met as per the STEPS. Nevertheless, this would leave coal demand significantly above the level in its SDS, where warming is limited to well-below 2C (yellow line, above).

According to the STEPS, rising is one of the key factors holding global coal use steady, despite rapid falls in developed economies, such as the US and EU.

Part of the reason for this increase in India is a large expected buildout of new coal-fired power stations, with 232GW of capacity built by 2040 in the STEPS, roughly doubling its and accounting for a third of global additions.

The IEA says India’s coal capacity growth could be cut “sharply”, if declines in the cost of battery storage are faster than expected. Solar and cheap storage could “reshape the evolution of India’s power mix”, the IEA says, offering a “very compelling economic and environmental proposition”.

It is also worth comparing the 232GW of new coal capacity expected by the IEA, with India’s current pipeline of , of which a quarter has been frozen in construction for years.

Another 510GW of new coal has been cancelled since 2010 due to competition from cheaper renewables, financial distress at utility firms and public opposition.

In addition, the Indian government has electricity demand growth, meaning existing coal capacity is running less than two-thirds of the time. Moreover, data for 2019 to date suggests India’s electricity .

The Indian government recently a highly ambitious target for solar, wind and biomass capacity to reach 450GW, potentially as soon as 2030, when the IEA STEPS outlook sees just 344GW having been added. If this target is met, then wind, solar and other low-carbon sources could largely meet rising demand without new coal, according to recent .

※ 全文及圖片詳見:()

作者

如果有一件事是重要的,如果能為孩子實現一個願望,那就是人類與大自然和諧共存。

於特有生物研究保育中心服務,小鳥和棲地是主要的研究對象。是龜毛的讀者,認為龜毛是探索世界的美德。

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

※帶您來看台北網站建置台北網頁設計,各種案例分享

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