美國各州急尋經費修路、電動車爽領補貼的日子將盡?

電動車爽領補貼、減免稅率的好日子快要結束?美國不少基礎建設早該翻修,各州為了尋找經費焦頭爛額,紛紛把腦筋動到電動車頭上。今(2017)年美國至少已有五州通過對電動車徵稅的法案,當中甚至包括對環保議題最為熱衷的加州。

CNBC 3日報導(見此),美國包括加州在內的不少州,已在今年通過對電動車加稅,一年徵收100-200美元不等。加州州長布朗(Jerry Brown)在今年春季通過法案時表示,安全和順暢的道路,不但能使加州成為更佳的居住地,也會提振州內經濟活動,增加數千個工作機會。

加州的決定,顯示市場對電動車的心態已有轉變。美國不少州原本都對環保汽車相當友善,提出減稅補貼等獎勵措施,鼓勵駕駛人換車。如今各州財政緊繃,道路又坑坑巴巴、亟待修整,電動車便成了眾矢之的。自2013年以來,美國24州、華盛頓哥倫比亞特區都已決定調高電動車的燃料稅(gas tax),其中加州把燃料稅調高12美分,以支應524億美元道路維修暨壅塞紓解方案的半數費用。

環保人士擔憂,這些費用可能會壓抑電動車的銷售量。不僅如此,購買電動車所享有的7,500美元聯邦減稅優惠,也會在電動車賣出20萬輛後遭到解除。根據汽車銷售暨資訊網站Edmunds.com估計,電動車對整體汽車市場的佔有率目前僅有0.6%,銷售量成長率則從2013年的227%,驟降至2016年的5%。

Barronˋs Next 5月9日報導,Edmunds當時就悲觀預測(見此),電動車聯邦減稅優惠終結將摧毀美國電動車車市。當局規定,車商的前20萬名客戶,可以獲得補助,如今特斯拉(Tesla)已售出將近10萬輛電動車,估計明年優惠就會結束。

特斯拉平價車款「Model 3」定價3.5萬美元,扣掉7,500美元補貼之後,買家等於只要付2.75萬美元,差距極為明顯。特斯拉想打入大眾車市,必須對上2萬美元的汽油車和油電混合車,少了優惠之後,兩者價差更為懸殊。

以美國喬治亞州為例,該州取消購買電動車的5,000美元稅務優惠之後,買氣急凍。有稅務優惠時,喬治亞州佔全美電動車銷售的17%;取消之後,銷售比重驟降至2%。Edmunds據此推論,補助結束後,電動車市將崩盤。Edmunds報告指出,高檔電動車較不受稅務優惠影響,但是一般買家會在意補貼。補助終結後,電動車廠必須大砍售價,才能維持買氣。

(本文內容由授權使用。圖片出處:public domain CC BY 0)

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

Jaguar 宣布進軍電動車市場,要來挑戰Tesla

各個車廠看到電動車的趨勢,不願意讓Tesla 再繼續引領風潮,包括Jaguar 也將在2018 年下半年發表電動車車款。

Jaguar 的新電動車概念車I-PACE 將在2018 年下半年推出,將是Jaguar 第一台純電動車。性能方面具備700Nm 高扭力,400PS 馬力與4 秒內完成0~100km/h 加速的超高性能,相信是追求速度和零排放車主的選擇。

Jaguar 決定推出全電動車,意味著要跟Tesla 在SUV 市場短兵相接。由於電動車不用傳統車子的馬達系統,車內空間可以更寬敞讓乘客和駕駛更舒適。

(合作媒體:。圖片出處:Jaguar)

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

【其他文章推薦】

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

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

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

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

上海新能源汽車展8月23舉行 吉利將攜帝豪PHEV亮相

進入2017年以來,上海市新能源汽車推廣應用和產業發展繼續保持高增長,1-5月新能源汽車推廣上牌數量達到10699輛。據瞭解,目前在上海市場上銷售的新能源車型累計超過100款,其中本地品牌占比為35%,其他省市品牌占比達到65%,市場累計推廣前5位的品牌依次為比亞迪、榮威、北汽、奇瑞、Tesla。

當前,上海已成為新能源汽車全球保有量最大的城市,吉利汽車自然不會放過這個巨大的市場。在最近上海市經信委公佈的4批新能源汽車備案資訊表中,吉利分別在第三批、第四批目錄中均有車型進入。據悉,吉利進入上海市新能源汽車備案資訊表中的車型為吉利帝豪EV300及吉利帝豪PHEV。

吉利帝豪EV300自推出以來,頗受市場的歡迎,今年5月還登頂了新能源汽車單車銷量排行板的第一位,而帝豪PHEV作為吉利旗下首款插電式混合動力車型,自公佈以來也是備受關注。

據瞭解,吉利帝豪PHEV外觀上與吉利帝豪EV基本相同。內飾方面,帝豪PHEV配備三輻式真皮方向盤並集成了CCS定速巡航、多媒體播放、語音控制等控制按鈕。而與帝豪EV不同的是,在中控部分帝豪PHEV增加了旋鈕式檔位,使車輛可在純電動、混合動力等模式中進行切換,增強了操作的便利性及駕駛體驗。

最亮眼的部分是帝豪PHEV採用了被稱為“聯擎”的功率分流式混合動力技術,搭載代號為JLγ-4G15H的1.5L發動機與兩台高性能電機和11.3kWh的三元鋰電池組組成的插電式混合動力系統。新車最高時速可達175km/h,NEDC工況油耗1.5L/100km,HEV模式下綜合工況油耗5.1L/100km,NEDC工況下純電續航里程61km。

作為全國插電式混合動力最大銷售城市,吉利帝豪PHEV本次順利進入上海新能源汽車目錄無疑是個極好的信號。為了與各位大咖搶佔市場份額,吉利汽車將攜帝豪EV300,帝豪PHEV亮相2017上海國際新能源汽車產業博覽會。其中帝豪PHEV是進入上海新能源汽車目錄後,首度亮相上海。

據瞭解,2017上海國際新能源汽車產業博覽會是由充電設施線上網、廣東省充電設施協會、廣東省新能源汽車產業協會、中國土木工程學會城市公共交通學會和振威展覽股份聯合舉辦,展示面積達45000平米,參展企業涵蓋了整車、核心三電(電池、電機、電控)、充電設備等產業板塊,是我國新能源汽車產業領域最專業的展覽展示和技術交流的綜合性展會平臺。

除吉利外,比亞迪、申龍客車、珠海銀隆、上汽集團、上饒客車、中植新能源、中通、江淮、眾泰、知豆、南京金龍、成功汽車、新吉奧集團、瑞馳新能源、福汽新龍馬等新能源汽車企業,以及精進電動、英威騰、東風電機、力神、沃特瑪、國軒高科、地上鐵、特來電、科陸、巴斯巴、萬馬專纜、奧美格、瑞可達等核心三電及零部件知名企業將亮相本次展會。

參觀預登記,請點擊:

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

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

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

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

Volvo 兩年後只生產電動車,中國政府是幕後推手

  Volvo 宣布要讓內燃機引擎退場,2019 年生產車款全面配備電動引擎,正式從生產傳統汽車轉向電動車,其實Volvo 此舉的最大幕後推手是近年積極發展綠能的中國政府,被中資買下的Volvo 只是配合中國政策布局。   華爾街日報(WSJ)分析指出,中國是全球最大汽車市場,因此中國政策一舉一動對產業變化是牽一髮動全身,隨著中國治理空汙政策逐步兌現,汽車大廠不得不跟著改變策略、加緊跟上,更別說現在Volvo 的老闆是中國吉利汽車。   現在中國每年電動車銷售量可達50 萬台,超過美國與其他已開發國家,中國政府上月更新電動車政策,旨在鼓勵生產更大容量電池的電動車,在此政策下生產高品質電動車的廠商將受惠,但不利於在電動車領域發展較晚的企業。   電動車快速成長打破市場對中國抑制生產的謠言。但是中國政府的確要稍微踩煞車,如同過去避免太陽能面板到風力渦輪機生產過剩的現象。政策調整後,現在生產高品質,電池續航力更久的電動車製造商,若沒有達到綠色汽車產量標準所面臨的罰則較輕,且生產高品質電動車可以在中國新能源汽車積分制度上中賺取積分,在市場上賣給其他負積分的廠商,成為一筆收入來源。   中國政府希望政策調整能夠在淘汰低品質產品同時保持生產力道。德國戴姆勒(Daimler)近日表示,將升級與中國合資企業共同使用的設備,以生產更多電動車。福特也表示將在中國生產電動車,計劃在2025 年前將七成電動車產能移往中國。   福斯(Volkswagen)電動車設計也是以中國市場為核心,目標是在2025 年前每年賣出100 萬台電動車,其中六成銷往中國。日本大廠也不放過,本田(Honda)汽車宣布要在2018 年於中國上市純電動車。   不過新政策對中國最大SUV 製造商長城汽車而言沒有好處,因為SUV 賣得太好,因此長城汽車的燃油消耗仍遠高於政府規定的目標,市場認為長城汽車短期內不會發展電動車,而吉利汽車相較同業可獲得較大利益。   中國十三五計畫明訂發展電動車產業,在政策扶植下已成為正在強勢發展的明星級產業,中國訂下2020 年讓500 萬輛電動車上路的目標。報導認為,中國政策加上全球汽車大廠的配合,將是推動電動車發展的最大幕後黑手。   (合作媒體:。圖片出處:pixabay CC0)  

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

【其他文章推薦】

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

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

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

圖解Elasticsearch的核心概念

本文講解大綱,分8個核心概念講解說明:

  • NRT
  • Cluster
  • Node
  • Document&Field
  • Index
  • Type
  • Shard
  • Replica

Near Realtime(NRT)近實時

Elasticsearch的核心優勢就是(Near Real Time NRT)近乎實時,我們稱之為近實時。
NRT有兩個意思,下面舉例說明下:

  • 從寫入索引數據到數據可以被搜索到有一個小延遲(大概1秒);

舉個例子:電商平台新上架一個新商品,1秒後用戶就可搜索到這個商品信息,這就是近實時。

  • 基於Elasticsearch執行搜索和分析可以達到秒級查詢

也舉個例子說明,比如我現在想查詢我在淘寶,最近一年都買過幾件商品,總共花了多少錢,最貴的商品多少錢,哪個月買到東西最多,什麼類型的商品買的最多這樣的信息,如果淘寶說,你要等待10分鐘才能出結果,你是不是很崩潰,這個延遲的時間就不是近實時,如果淘寶可以秒級別返回給你,就是近實時了。

下面畫一個圖,解釋下三個基本概念的

Cluster:集群

包含多個節點,每個節點屬於哪個集群是通過一個配置(集群名稱,默認是elasticsearch)來決定的,對於中小型應用來說,剛開始一個集群就一個節點很正常。集群的目的為了提供高可用和海量數據的存儲以及更快的跨節點查詢能力。

Node:節點

集群中的一個節點,節點也有一個名稱(默認是隨機分配的),節點名稱很重要(在執行運維管理操作的時候),默認節點會去加入一個名稱為“elasticsearch”的集群,如果直接啟動一堆節點,那麼它們會自動組成一個elasticsearch集群,當然一個節點也可以組成一個elasticsearch集群

Document&field:文檔和字段

document 是es中的最小數據單元,一個document可以是一條客戶數據,一條商品分類數據,一條訂單數據,通常用JSON數據結構表示,每個index下的type中,都可以去存儲多個document。一個document裏面有多個field,每個field就是一個數據字段。

相當於mysql里的行,可以簡單這麼理解,舉個例子。一個商品的文檔數據一條如下:

product document
{
  "product_id": "1000",
  "product_name": "mac pro 2019 款筆記本",
  "product_desc": "高性能,高分辨率,編程必備神器",
  "category_id": "2",
  "category_name": "电子產品"
}

Index:索引

包含一堆有相似結構的文檔數據,比如可以有一個客戶索引,商品分類索引,訂單索引,索引有一個名稱。
一個index包含很多document,一個index就代表了一類類似的或者相同的document。比如說建立一個product index,商品索引,裏面可能就存放了所有的商品數據,所有的商品document。

Type:類型

每個索引里都可以有一個或多個type,type是index中的一個邏輯數據分類,一個type下的document,都有相同的field,比如博客系統,有一個索引,可以定義用戶數據type,博客數據type,評論數據type。

商品index,裏面存放了所有的商品數據,商品document

但是商品分很多種類,每個種類的document的field可能不太一樣,比如說電器商品,可能還包含一些諸如售後時間範圍這樣的特殊field;生鮮商品,還包含一些諸如生鮮保質期之類的特殊field

type,日化商品type,電器商品type,生鮮商品type

日化商品type:product_id,product_name,product_desc,category_id,category_name
電器商品type:product_id,product_name,product_desc,category_id,category_name,service_period
生鮮商品type:product_id,product_name,product_desc,category_id,category_name,eat_period

每一個type裏面,都會包含一堆document

{
“product_id”: “2”,
“product_name”: “長虹電視機”,
“product_desc”: “4k高清”,
“category_id”: “3”,
“category_name”: “電器”,
“service_period”: “1年”
}

{
“product_id”: “3”,
“product_name”: “基圍蝦”,
“product_desc”: “純天然,冰島產”,
“category_id”: “4”,
“category_name”: “生鮮”,
“eat_period”: “7天”
}

Shard 分片,也稱 Primary Shard

單台機器無法存儲大量數據,es可以將一個索引中的數據切分為多個shard,分佈在多台服務器上存儲。有了shard就可以橫向擴展,存儲更多數據,讓搜索和分析等操作分佈到多台服務器上去執行,提升吞吐量和性能。

每個shard都是一個lucene index。

Replica 副本,也稱 Replica Shard

任何一個服務器隨時可能故障或宕機,此時shard可能就會丟失,因此可以為每個shard創建多個replica副本。replica可以在shard故障時提供備用服務,保證數據不丟失,多個replica還可以提升搜索操作的吞吐量和性能。

primary shard(建立索引時一次設置,不能修改,默認5個),

replica shard(隨時修改數量,默認1個),

默認每個索引10個shard,5個primary shard,5個replica shard,最小的高可用配置,是2台服務器。

相關索引解釋說明:

  • index包含多個shard
  • 每個shard都是一個最小工作單元,承載部分數據,lucene實例,完整的建立索引和處理請求的能力
  • 增減節點時,shard會自動在nodes中負載均衡
  • primary shard和replica shard,每個document肯定只存在於某一個primary shard以及其對應的replica shard中,不可能存在於多個primary shard
  • replica shard是primary shard的副本,負責容錯,以及承擔讀請求負載
  • primary shard的數量在創建索引的時候就固定了,replica shard的數量可以隨時修改
  • primary shard的默認數量是5,replica默認是1,默認有10個shard,5個primary shard,5個replica shard
  • primary shard不能和自己的replica shard放在同一個節點上(否則節點宕機,primary shard和副本都丟失,起不到容錯的作用),但是可以和其他primary shard的replica shard放在同一個節點上

索引在集群中分配圖:

本文由博客一文多發平台 發布!

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

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

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

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

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

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

貪心算法(會場安排問題、區間選點)

學習算法課程之後的第一次記錄,漸漸的,程序設計考慮的因素增多,程序=數據結構+算法,這個等式讓我深有體會。從開始簡單的C++編程,再到選擇合適數據結構,現在需要更進一步,從算法層次上考慮程序執行的效率。我對算法的理解是用更少的開銷獲得更優的執行效果。

分治法、動態規劃在此之前沒有記錄下來,學到貪心算法的時候,覺得需要總結一下學過的東西,也能更好的理解。動態規劃的設計,要滿足最優子結構性質和重疊子問題,採用自底向上的策略,計算出最優值,找到整體最優解。這個過程有時候挺難的,主要在寫出遞歸式,要自底向上填表。貪心策略有點像動態規劃,但在一些方面是不同的,有時候貪心算法的思想更容易想到。它要滿足子問題最優而得到整體最優?兩個條件:最優子結構性質和貪心選擇性質。滿足貪心選擇性質一定滿足最優子結構性質,而滿足最優子結構性質不一定滿足貪心選擇性質,比如背包問題可以用貪心算法解決,而0-1背包問題只能用動態規劃。

典型的貪心問題活動安排,有n個活動,給出開始時間和結束時間,要盡可能安排多的活動(時間互相不衝突)。解決這個問題正確的貪心思想是以每個活動結束時間為比較變量,按結束時間升序排好活動次序,接着就進行比較選擇。而會場安排問題與活動又有些不同之處,下面是我的解題過程。

7-2 會場安排問題 (20 分)

假設要在足夠多的會場里安排一批活動,並希望使用盡可能少的會場。設計一個有效的 貪心算法進行安排。(這個問題實際上是著名的圖着色問題。若將每一個活動作為圖的一個 頂點,不相容活動間用邊相連。使相鄰頂點着有不同顏色的最小着色數,相應於要找的最小 會場數。)

輸入格式:

第一行有 1 個正整數k,表示有 k個待安排的活動。 接下來的 k行中,每行有 2個正整數,分別表示 k個待安排的活動開始時間和結束時間。時間 以 0 點開始的分鐘計。

輸出格式:

輸出最少會場數。

輸入樣例:

5
1 23
12 28
25 35
27 80
36 50 

輸出樣例:

3
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
    int begin;
    int end;
    int flag;//標記該活動是否被安排,0表示未安排,1表示已安排 
}t[10001];
int cmp(const node &a,const node &b)//比較規則:以結束時間升序排列 
{ 
    return a.end<b.end;
 } 
int main()
{
    int i,j,n;
    node temp;
    cin>>n;
    for(i=0;i<n;i++) 
    {
        cin>>t[i].begin>>t[i].end;
        t[i].flag=0;
    }
    sort(t,t+n,cmp);
        
    int sum=0;//總共需要的會場數量 

    for(i=0;i<n;i++)//方法2 
    {
        if(!t[i].flag)//找到未安排的活動,進行場地安排 
        {
            sum++;
            int p=i;
            for(j=p+1;j<n;j++)//當前活動結束時間與下一個活動開始不相交 ,則安排到同一個會場 
            {
                if(t[p].end<=t[j].begin&&!t[j].flag)
                {
                    p=j;t[j].flag=1;
                }
            }
            t[i].flag=1;
        }
    }

    cout<<sum;
    return 0;
}

View Code

貪心策略為:把盡可能多的時間互不衝突的活動安排到一個會場,若活動時間交叉,則在安排到另一個會場。

將所有活動按結束時間升序排列,利用sort函數,自定義cmp方法。循環體中,每次可以找到還沒有安排的活動,並以這個活動搜索能同時容納到一個會場的其他活動(這一步嵌套在內層循環中),經過兩層循環,把所有活動全部安排好,這時也已經計算出需要的會場數量sum。

類似的問題是區間選點

7-10 選點問題 (15 分)  數軸上有n個閉區間[ai, bi]。取盡量少的點,使得每個區間內都至少有一個點(不同區間內含的點可以是同一個)。

輸入格式:

第一行一個数字n,表示有n個閉區間。 下面n行,每行包含2個数字,表示閉區間[ai, bi]

輸出格式:

一個整數,表示至少需要幾個點

輸入樣例:

在這裏給出一組輸入。例如:

3
1 3
2 4
5 6

輸出樣例:

在這裏給出相應的輸出。例如:2

開始想找出幾個區間共同段,並且記錄每個共同段中包含哪些區間,這樣算出最少選點。後來發現覺得這個想法其實可以簡化一下,策略為:以右端為擋板,看看前面是否包含其他區間,如果是,則不記數,反之,說明沒有共同段,需要計數並且移動擋板位置繼續尋找。貪心策略是選擇區間右端點,保證能夠包含更大交叉段,選的點最少。

#include<bits/stdc++.h>
using namespace std;
struct dot{
    int l,r;
    bool v[10001];
}dots[10001];

int cmp(const dot &a,const dot &b)//比較規則,按區間右端點升序排列 
{
    return a.r<b.r;
} 

int main()
{
    int n,i,j,count=1,select;
    cin>>n;
    for(i=0;i<n;i++)
        cin>>dots[i].l>>dots[i].r;
    sort(dots,dots+n,cmp);//預處理,將區間按規則排好序,方便後續比較 
    select=dots[0].r;
    //貪心策略是選擇區間右端點,保證能夠包含更大交叉段,選的點最少 
    for(i=1;i<n;i++)//每次將當前選擇的一個區間的右端點與下一個(或者同一區間,可忽略)左端比較 
    {
        if(dots[i].l>select)//如果沒有交叉,選點+1,並以此區間右端為新一輪比較的點 
        {
            count++;
            select=dots[i].r;
        }
    }
    cout<<count;
    return 0;
}

View Code

學習算法之後,發現解決問題上需要思維上的改變,程序設計之前的算法選擇很重要,還要向大佬們學習,典型算法的學習研究真是博大精深呀!

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

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

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

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

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

WeTest明星工具-移動端性能測試PerfDog初探

在十一月初,騰訊就官宣了一則消息,騰訊WeTest明星工具-PerfDog面向全球發布。官宣介紹如下:。我在看到該新聞時,有種大開眼界的感覺,移動端的性能測試原來可以這麼簡單。今天閑暇之餘,來了一波初探,簡單體驗了一番。

軟件性能數據採集

我們先來了解下通過該工具能採集到哪些性能數據:

PerfDog支持移動平台所有應用程序(遊戲、APP應用、瀏覽器、小程序等)及Android模擬器,桌面應用程序PerfDog支持在Windows和Mac機器使用運行。在iOS和Android平台獲取性能參數如下:

iOS平台 (與蘋果官方Xcode工具參數對齊一致)

  • Screenshot
  • FPS(1秒內遊戲畫面或者應用界面真實平均刷新次數,俗稱幀率/FPS)
       1) Avg(FPS):平均幀率(一段時間內平均FPS)
       2) Var(FPS):幀率方差(一段時間內FPS方差)
       3) Drop(FPS):降幀次數(平均每小時相鄰兩個FPS點下降大於8幀的次數)
  • Jank(1s內卡頓次數。iOS9.1以下系統暫時不支持。類似Android的Jank卡頓和iOS的FramePacing平滑度統計原理。幀率FPS高並不能反映流暢或不卡頓。比如:FPS為50幀,前200ms渲染一幀,后800ms渲染49幀,雖然幀率50,但依然覺得非常卡頓。同時幀率FPS低,並不代表卡頓,比如無卡頓時均勻FPS為15幀。所以,平均幀率FPS與卡頓無任何直接關係)
        PerfDog計算方法:同時滿足兩條件,則認為是一次卡頓Jank.
        1、 當前幀耗時>前三幀平均耗時2倍。
        2、 當前幀耗時>兩幀電影幀耗時(1000ms/24*2=84ms)。
        同時滿足兩條件,則認為是一次嚴重卡頓BigJank.
        1、 當前幀耗時>前三幀平均耗時2倍。
        2、 當前幀耗時>三幀電影幀耗時(1000ms/24*3=125ms)。
    計算思路:考慮視覺慣性,假設以前三幀的平均幀耗時為參考,作為vsync時間間隔,連續兩次vsync沒有新渲染畫面刷新,則認為是一次潛在卡頓,也就是說下一幀耗時大於前三幀平均幀耗時2倍,則認為一次潛在卡頓。同時單幀耗時滿足大於兩倍電影幀耗時1000ms/24*2 (由於人眼低於24幀才能辨別畫面不連續性),則認為是一次真正卡頓。同時若單幀耗時大於3倍電影幀耗時,則認為是一次嚴重卡頓。
    註解:為什麼是兩次vsync?GPU一般是3重緩衝buffer,當前幀已佔用一個buffer,即剩餘2緩衝buffer,人眼一般可容忍2幀延遲。 為什麼是兩幀電影幀耗時?低於24幀畫面,人眼就能感知到畫面不連續性,電影一般都是24幀。即電影幀耗時1000ms/24=41.67ms,兩幀電影幀耗時也就是41.67ms*2,三幀電影幀耗時是41.67ms*3。
       1) BigJank:1s內頓嚴重卡次數
       2) Jank(/10min):平均每10分鐘卡頓次數。
       3) BigJank(/10min):平均每10分鐘嚴重卡頓次數
  • FTime(上下幀畫面显示時間間隔,即認為幀耗時,iOS9.1以下系統暫時不支持。)
       1) Avg(FTime):平均幀耗時 
       2) Delta(FTime):增量耗時(平均每小時兩幀之間時間差>100ms的次數)
  • CPU Usage(Total整機/App進程,統計結果合Xcode一致)
  • Memory (是統計FootPrint,注:OOM與FootPrint有關,與系統、機型無關。只與RAM有關,如1G內存機器。FootPrint超過650MB,引發OOM)。受iOS平台限制,暫時無法獲取ios10及以下系統的memory。後續版本增加。如做性能測試,建議升級iOS系統版本
  • Xcode Memory (XCode Debug Gauges統計方式即XCode Memory)。受iOS平台限制,暫時無法獲取ios10及以下系統的Xcode Memory。後續版本增加。如做性能測試,建議升級iOS系統版本
  • Real Memory(Xcode Instrument統計方式即Real Memory,實際佔用物理內存。注:物理內存與系統策略有關,關注意義不大)
  • Virtual Memory(虛擬內存)
  • Wakeups(線程喚醒次數)。注:超過150進程很大可能會被系統kill
  • CSwitch(上下文切換測試)。注:單核超過14000進程會被系統Kill
  • GPU Utilization(Render/Tilter/Device)
       1) Render:渲染器利用率(像素着色處理階段,若佔比高,說明是PS階段出現瓶頸,shader過於複雜或紋理大小、採樣複雜等) 
       2) Tilter:Tilter利用率(頂點着色處理階段,若佔比高,說明是VS階段出現瓶頸,頂點數太多等原因)
       3) Device:設備利用率(整體GPU利用率)
  • Network(Recv/Send,測試目標進程流量,和Xcode結果一致)
  • Battery Power(整機實時Current電流、Voltage電壓、Power功率)(注:和Xcode Instrument結果一致)
  • Log(系統調試日誌信息)

Android平台

  • Screenshot
  • FPS(1秒內遊戲畫面或者應用界面真實平均刷新次數,俗稱幀率/FPS)
       1) Avg(FPS):平均幀率(一段時間內平均FPS)
       2) Var(FPS):幀率方差(一段時間內FPS方差)
       3) Drop(FPS):降幀次數(平均每小時相鄰兩個FPS點下降大於8幀的次數)
  • Jank(1s內卡頓次數。解釋說明如iOS平台說明)
       1) BigJank:1s內嚴重卡頓次數
       2) Jank(/10分鐘):平均每10分鐘卡頓次數
       3) BigJank(/10分鐘):平均每10分鐘嚴重卡頓次數 
  • FTime(上下幀畫面显示時間間隔,即認為幀耗時)
       1) Avg(FTime):平均幀耗時
       2) Delta(FTime):增量耗時(平均每小時兩幀之間時間差>100ms的次數)
  • CPU Usage(Total整機/App目標進程,統計結果和Android Studio Profiler一致)
  • CPU Clock(各個CPU核心的頻率和使用率)
  • Memory (PSS Memory,統計結果和Android Java API標準結果一致,與Meminfo也一致。注:部分三星機器系統修改了Meminfo底層統計方式,導致Meminfo與Java AP統計結果不一致,新出三星機器已修復)
  • Swap Memory (Swap Memory)
  • Virtual Memory
  • Memory Detail(NativePSS、GFX、GL、Unknown)
  • GPU Usage(目前僅支持高通芯片手機)
  • GPU Frequency(目前僅支持高通芯片手機)
  • Network(Recv/Send)
  • CTemp(CPU溫度)
  • Battery Power(Current電流、Voltage電壓、Power功率)(注:與儀器測試誤差<3%左右)
  • Log(系統調試日誌信息)

上述內容來自官網使用文檔。我們了解了參數,就實際來操作一下吧。對於工具的介紹,網絡上都有,我就結合自己的實際體驗來說吧。

使用的基本流程

在自己實踐使用時,基本流程如下:

1.註冊賬號(只有註冊賬號后才能下載安裝包)

2.下載安裝包並解壓

3.在perfdog後台創建測試項目

4.打開可執行文件PerfDog.exe

5.使用註冊的賬號登錄

6.使用usb將手機和電腦連接(不能鎖屏,開啟調試模式)

7.選擇連接模式(wifi還是usb)

8.選擇app應用列表

9.配置要監控的數據

10.開始記錄數據

11.操作對應app

12.停止記錄數據(不能少於10S)

13.上傳記錄數據

14.進入perfdog後台查看性能數據

流程介紹

前五步操作就不講述了,大家都懂。我們直接從第六步說起,我使用的是ios設備。

連接設備

iOS: 則即插即用,用戶無需做任何操作。

Android: 有兩種模式,非安裝模式和安裝模式。

  • a. 非安裝模式:

    手機即插即用,無需任何設置及安裝,使用非常簡單,但手機屏幕上沒有實時性能數據显示。

  • b. 安裝模式:

    需要在手機上自動安裝PerfDog.apk,手機屏幕上有實時性能數據显示。(請開啟Debug調試模式、允許USB安裝和PerfDog懸浮窗管理權限),啟動PC版PerfDog.exe,則會在手機上自動PUSH安裝PerfDog.apk,具體安裝類似各個手機廠商安裝第三方APP提示安裝即可。(注:由於很多手機安裝需要賬號密碼,導致無法自動安裝,如果自動安裝失敗,則會把安裝文件PerfDog.apk釋放到當前文件夾里,手動安裝PerfDog.apk即可)。

這裏重點說明下Android平台下,LMK和Swap這兩個參數意義:

LMK:Android平台下OOM與遊戲進程內存大小無關,主要是系統剩餘物理內存有關。系統剩餘物理內存小於LMK,則會引起OOM。

Swap: 系統進程用到zram/vnswap內存壓縮技術。不同手機系統啟用Swap memeroy大小不同。

測試模式

通過usb連接電腦後,出現如下界面,可以選擇測試模式:

USB模式測試:

  USB連線,在設備列表選擇USB圖標設備進行USB模式測試(插線模式測試功率無任何意義)。

WIFI模式測試(測試功率):

  USB連線后,在設備列表選擇WIFI圖標設備進行WIFI模式測試。WIFI檢測連接成功后,拔掉USB連接線。(注:需要PC和被測手機連接同一WIFI,WIFI檢測連接成功后,拔掉被測手機USB線(插線模式測試功率無任何意義))。

在實踐中,USB和WiFi模式我都有使用。選擇模式后,界面會展示設備的詳細信息,如下:

選擇測試應用

選擇模式后,則可以選擇要測試的應用了(當前手機中的所有app都可以被選擇),如下頁面:

選擇對應被測應用,並操作對應的app,界面展示如下:

注意點:Android平台,安裝模式下,手機屏幕左上角有實時性能數據显示(Android手機請打開PerfDog懸浮窗管理權限,否則手機上不會显示性能參數)。

開啟懸浮權限

android設備中的界面性能參數显示如下:

功能介紹

1.性能參數配置

性能參數可在界面中配置,點擊界面中的+號即可,如下:

①點擊對應條目參數,顏色會變深,圖表數據則會展示在界面中

②勾選對應條目參數,表示需要收集該數據

2.記錄保存

點擊右側的藍色開始按鈕,則表示在記錄數據,如下:

需要注意的是:記錄時間不能少於10S。少於10S,則會提示如下信息:

點擊按鈕后,記錄會停止記錄並保存數據,如下:

2.1 提交記錄到perfdog後台

可以修改名稱,點擊confirm,數據會上傳到perfdog的後台,如下:

可以查看詳細的性能數據,如下所示:

2.2 記錄保存到本地

勾選保存按鈕,數據就會保存到本地,如下:

可以打開excel文件查看對應的性能數據:

3.數據回放

點擊perfdog界面上的文件夾按鈕,選擇對應的本地數據,即可以回放記錄,操作如下:

可在界面查看回放結果,如下:

4.批註及標定

雙擊鼠標左鍵,增加批註,再次雙擊,則取消批註。

單擊鼠標左鍵,則增加標定,再次點擊則重新標定。

增加了批註和標定的界面如下所示,紅色為批註,淡紫色為標定:

5.性能參數分析

5.1 數據統計

可以選擇一個時間段內的數據,進行統計,如下:

5.2 設置性能參數統計分析閾值

在perfdog界面中的setting下,可以配置,如下:

5.3 保存框選數據

對某一時間段內的數據框選后,可以單獨保存片段,在框選範圍內,右鍵即可,如下:

6.場景標籤

通過標籤按鈕給性能數據打標籤,鼠標左鍵雙擊顏色區域可修改對應區域標籤名

7.日誌記錄

在perfdog界面,可以查看對應日誌,也可以設置查看日誌的等級,如下:

在嘗試WIFI模式時,發現log按鈕勾選不了。

8.停止功能

停止測試應用,不需要拔掉數據線,或者斷開連接,在選擇應用的界面中,選擇NULL即可,如下:

9.截圖錄屏

連接安卓設備,並使用安裝模式,可配置截屏參數,如下:

界面就會記錄操作的過程,如下所示:

如此記錄是不是很明了?但這種用法會影響性能參數,實際用途中不推薦。如果覺得新鮮,可以嘗試使用即可。

PerfDog後台使用

1.邀請人員

可以邀請對應人員一起維護測試項目

2.數據共享

數據共享后,可以在任務數據中查看明細,可按android、ios區分,以及app包的版本,設備版本來查看。

使用注意點

1.設備連接

iOS: 若PerfDog檢測不到連接手機或無法測試,請先安裝確保最新iTunes是否能連上手機。

Android: 請開啟手機Debug調試模式及允許USB安裝。

2.截圖記錄影響性能

截屏記錄影響性能(整體FPS影響<=1。小米5:CPU=1%左右。IPhone7P:CPU<2%),若無需請不要開啟截屏。

總結

使用PerfDog工具下來,整體有以下幾點感受。

1.對性能指標的測試,更加便捷;

2.易操作

3.記錄支持回放

4.數據便於管理與查看

PerfDog工具是款不錯的性能測試工具,點贊一波。

最後,附上官方的操作手冊:

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

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

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

[機器學習筆記]kNN進鄰算法

K-近鄰算法

一、算法概述

(1)採用測量不同特徵值之間的距離方法進行分類

  • 優點: 精度高、對異常值不敏感、無數據輸入假定。
  • 缺點: 計算複雜度高、空間複雜度高。

(2)KNN模型的三個要素

kNN算法模型實際上就是對特徵空間的的劃分。模型有三個基本要素:距離度量、K值的選擇和分類決策規則的決定。

  • 距離度量

    距離定義為:
    \[L_p(x_i,x_j)=\left( \sum^n_{l=1} |x_i^{(l)} – x_j^{(l)}|^p \right) ^{\frac{1}{p}}\]
    一般使用歐式距離:p = 2的個情況
    \[L_p(x_i,x_j)=\left( \sum^n_{l=1} |x_i^{(l)} – x_j^{(l)}|^2 \right) ^{\frac{1}{2}}\]

  • K值的選擇

    一般根據經驗選擇,需要多次選擇對比才可以選擇一個比較合適的K值。

    如果K值太小,會導致模型太複雜,容易產生過擬合現象,並且對噪聲點非常敏感。

    如果K值太大,模型太過簡單,忽略的大部分有用信息,也是不可取的。

  • 分類決策規則

    一般採用多數表決規則,通俗點說就是在這K個類別中,哪種類別最後就判別為哪種類型

二、實施kNN算法

2.1 偽代碼

  • 計算法已經類別數據集中的點與當前點之間的距離
  • 按照距離遞增次序排序
  • 選取與但前點距離最小的k個點
  • 確定前k個點所在類別的出現頻率
  • 返回前k個點出現頻率最高的類別作為當前點的預測分類

2.2 實際代碼

def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

三、實際案例:使用kNN算法改進約會網站的配對效果

我的朋友阿J一直使用在線約會軟件尋找約會對象,他曾經交往過三種類型的人:

  • 不喜歡的人
  • 感覺一般的人
  • 非常喜歡的人

步驟:

  • 收集數據
  • 準備數據:也就是讀取數據的過程
  • 分析數據:使用Matplotlib畫出二維散點圖
  • 訓練算法
  • 測試算法
  • 使用算法

3.1 準備數據

樣本數據共有1000個,3個特徵值,共有4列數據,最後一列表示標籤分類(0:不喜歡的人;1:感覺一般的人;2:非常喜歡的人)

特徵

  • 每年獲得的飛行常客里程數
  • 玩視頻遊戲所好的時間百分比
  • 每周消費的冰淇淋公斤數

部分數據如下:

40920   8.326976    0.953952    3
14488   7.153469    1.673904    2
26052   1.441871    0.805124    1
75136   13.147394   0.428964    1
38344   1.669788    0.134296    1
72993   10.141740   1.032955    1
35948   6.830792    1.213192    3
42666   13.276369   0.543880    3
67497   8.631577    0.749278    1
35483   12.273169   1.508053    3

讀取數據(讀取txt文件)

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

3.2 分析數據:使用Matplotlib創建散點圖

初步分析
import matplotlib
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.set_xlabel("玩視頻遊戲所耗時間百分比")
ax.set_ylabel("每周消費的冰淇淋公斤數")
plt.show()

因為有三種類型的分類,這樣看的不直觀,我們添加以下顏色

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
ax.set_xlabel("玩視頻遊戲所耗時間百分比")
ax.set_ylabel("每周消費的冰淇淋公斤數")
plt.show()

通過都多次的嘗試后發現,玩遊戲時間和冰淇淋這個兩個特徵關係比較明顯

具體的步驟:

  • 分別將標籤為1,2,3的三種類型的數據分開
  • 使用matplotlib繪製,並使用不同的顏色加以區分
datingDataType1 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==1])
datingDataType2 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==2])
datingDataType3 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==3])
                   

fig, axs = plt.subplots(2, 2, figsize = (15,10))
axs[0,0].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
axs[0,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
axs[1,0].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
type1 = axs[1,1].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
type2 = axs[1,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
type3 = axs[1,1].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
axs[1,1].legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
axs[1,1].set_xlabel("玩視頻遊戲所耗時間百分比")
axs[1,1].set_ylabel("每周消費的冰淇淋公斤數")

plt.show()

3.3 準備數據:數據歸一化

通過上面的圖形繪製,發現三個特徵值的範圍不一樣,在使用KNN進行計算距離的時候,數值大的特徵值就會對結果產生更大的影響。

數據歸一化:就是將幾組不同範圍的數據,轉換到同一個範圍內。

公式: newValue = (oldValue – min)/(max – min)

def autoNorm(dataSet):
    minVals = dataSet.min(0) # array([[1,20,3], [4,5,60], [7,8,9]])   min(0) = [1, 5, 3]
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normData = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normData = (dataSet - tile(minVals, (m,1)))/tile(ranges,(m,1))
    return normData

3.4 測試算法

我們將原始樣本保留20%作為測試集,剩餘80%作為訓練集

def datingClassTest():
    hoRatio = 0.20  
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:,:],datingLabels[numTestVecs:],3)
        if (classifierResult != datingLabels[i]): 
            errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)

運行結果

the total error rate is: 0.080000
16.0

四、源代碼

from numpy import *
import operator
from os import listdir

import matplotlib
import matplotlib.pyplot as plt
    
## KNN function
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize,1)) - dataSet
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

# read txt data
def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector


def autoNorm(dataSet):
    minVals = dataSet.min(0) # array([[1,20,3], [4,5,60], [7,8,9]])   min(0) = [1, 5, 3]
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normData = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normData = (dataSet - tile(minVals, (m,1)))/tile(ranges,(m,1))
    return normData
    
    
    
    
def drawScatter1(datingDataMat, datingLabels):
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']

    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
    ax.set_xlabel("玩視頻遊戲所耗時間百分比")
    ax.set_ylabel("每周消費的冰淇淋公斤數")
    plt.show()
    
def drawScatter2(datingDataMat, datingLabels):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2])
    ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
    ax.set_xlabel("玩視頻遊戲所耗時間百分比")
    ax.set_ylabel("每周消費的冰淇淋公斤數")
    plt.show()
    
    
def drawScatter3(datingDataMat, datingLabels):
    datingDataType1 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==1])
    datingDataType2 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==2])
    datingDataType3 = array([[x[0][0],x[0][1],x[0][2]] for x in zip(datingDataMat,datingLabels) if x[1]==3])

    fig, axs = plt.subplots(2, 2, figsize = (15,10))
    axs[0,0].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
    axs[0,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
    axs[1,0].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
    type1 = axs[1,1].scatter(datingDataType1[:,0], datingDataType1[:,1], s = 20, c = 'red')
    type2 = axs[1,1].scatter(datingDataType2[:,0], datingDataType2[:,1], s = 30, c = 'green')
    type3 = axs[1,1].scatter(datingDataType3[:,0], datingDataType3[:,1], s = 40, c = 'blue')
    axs[1,1].legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
    axs[1,1].set_xlabel("玩視頻遊戲所耗時間百分比")
    axs[1,1].set_ylabel("每周消費的冰淇淋公斤數")

    plt.show()
    
    
    
def datingClassTest():
    hoRatio = 0.20  
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
    normMat = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:,:],datingLabels[numTestVecs:],3)
        if (classifierResult != datingLabels[i]): 
            errorCount += 1.0
    print ("the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print (errorCount)
    
    
datingDataMat, datingLabels = file2matrix("datingTestSet2.txt")

drawScatter1(datingDataMat, datingLabels)
drawScatter2(datingDataMat, datingLabels)
drawScatter3(datingDataMat, datingLabels)
 
datingClassTest()

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

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

ES6 Map 原理

ES6的Map的鍵可以是任意的數據結構,並且不重複。

那麼map的底層原理是啥呢?

Map利用鏈表,hash的思想來實現。

首先,Map可以實現刪除,而且刪除的數據可以是中間的值。而鏈表的優勢就是在中間的任意位置添加,刪除元素都非常快,不需要移動其他元素,直接改變指針的指向就可以。。

而在存儲數據很多的情況下,會導致鏈條過長,導致查找效率慢,所以我們可以創建一個桶(存儲對象的容器),根據hash(把散列的值通過算法變成固定的某值)來平局分配數據,防止鏈條過長。

 

 

如下圖:桶裏面有3個位置,每一個位置都是一個對象,通過next屬性指向下一個對象來把沒有關聯的對象聯到一起。

 

 

 

把Map屬性值和屬性名都存到對象的值里。

簡單模擬Map,代碼如下:

function Mymap() {  //構造函數
    this.init();
}
//初始化函數,創建桶(數組),每個位置都是一個對象,每個對象的屬性上設置next屬性,並且初始化為null。 Mymap.prototype.init = function () { this.tong = new Array(8); for (var i = 0; i
< 8; i++) { this.tong[i] = new Object(); this.tong[i].next = null; } }; //添加數據。 Mymap.prototype.set = function (key, value) { var index = this.hash(key); //獲取到當前設置的key設置到那個位置上 var TempBucket = this.tong[index]; //獲取當前位置的對象 while (TempBucket.next) { //遍歷如果當前對象鏈接的下一個不為空 if (TempBucket.next.key == key) { //如果要設置的屬性已經存在,覆蓋其值。 TempBucket.next.value = value; return; //return ,不在繼續遍歷 } else { TempBucket = TempBucket.next; //把指針指向下一個對象。 } } TempBucket.next = { //對象的next是null ,添加對象。 key: key, value: value, next: null } };
//查詢數據 Mymap.prototype.get = function (key) { var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.key == key){ return TempBucket.value; }else{ TempBucket = TempBucket.next; } } return undefined; }
//刪除數據 Mymap.prototype.delete = function(key){ var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.next.key == key){ TempBucket.next = TempBucket.next.next; return true; }else{ TempBucket = TempBucket.next; } } }
//看當前屬性是否存在 Mymap.prototype.has = function(key){ var index = this.hash(key); var TempBucket = this.tong[index]; while(TempBucket){ if(TempBucket.key == key){ return true; }else{ TempBucket = TempBucket.next; } } return false; }
//清空這個map Mymap.prototype.clear = function(){ this.init(); } //使設置的屬性平均分配到每個位置上,使得不會某個鏈條過長。 Mymap.prototype.hash = function (key) { var index = 0; if (typeof key == "string") { for (var i = 0; i < 3; i++) { index = index + isNaN(key.charCodeAt(i)) ? 0 : key.charCodeAt(i); } } else if (typeof key == 'object') { index = 0; } else if (typeof key == 'number') { index = isNaN(key) ? 7 : key; } else { index = 1; } return index % 8; } var map = new Mymap(); //使用構造函數的方式實例化map

map.set('name','zwq');
map.get('name');
map.has('name);

 

 

 

 

 

 

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

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

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

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

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

組件設計 —— 重新認識受控與非受控組件

重新定義受控與非受控組件的邊界

對非受控組件與受控組件作了如圖中下劃線的邊界定義。一經推敲, 該定義是缺乏了些完整性嚴謹性的, 比如針對非表單組件(彈框、輪播圖)如何劃分受控與非受控的邊界? 又比如非受控組件是否真的如文案上所說的數據的展示與變更都由 dom 自身接管呢?

在非受控組件中, 通常業務調用方只需傳入一個初始默認值便可使用該組件。以 Input 組件為例:

// 組件提供方
function Input({ defaultValue }) {
  return <input defaultValue={defaultValue} />
}

// 調用方
function Demo() {
  return <Input defaultValue={1} />
}

在受控組件中, 數值的展示與變更則分別由組件的 statesetState 接管。同樣以 Input 組件為例:

// 組件提供方
function Input() {
  const [value, setValue] = React.useState(1)
  return <input value={value} onChange={e => setValue(e.target.value)} />
}

// 調用方
function Demo() {
  return <Input />
}

有意思的一個問題來了, Input 組件到底是受控的還是非受控的? 我們甚至還可以對代碼稍加改動成 <Input defaultValue={1} /> 的最初調用方式:

// 組件提供方
function Input({ defaultValue }) {
  const [value, setValue] = React.useState(defaultValue)
  return <input value={value} onChange={e => setValue(e.target.value)} />
}

// 調用方
function Demo() {
  return <Input defaultValue={1} />
}

儘管此時 Input 組件本身是一個受控組件, 但與之相對的調用方失去了更改 Input 組件值的控制權, 所以對調用方而言, Input 組件是一個非受控組件。值得一提的是, 以非受控組件的使用方式去調用受控組件是一種反模式, 在下文中會分析其中的弊端。

如何做到不管對於組件提供方還是調用方 Input 組件都為受控組件呢? 提供方讓出控制權即可, 調整代碼如下:

// 組件提供方
function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />
}

// 調用方
function Demo() {
  const [value, setValue] = React.useState(1)
  return <Input value={value} onChange={e => setValue(e.target.value)} />
}

經過上述代碼的推演后, 概括如下: 受控以及非受控組件的邊界劃分取決於當前組件對於子組件值的變更是否擁有控制權。如若有則該子組件是當前組件的受控組件; 如若沒有則該子組件是當前組件的非受控組件。

職能範圍

基於調用方對於受控組件擁有控制權這一認知, 因此受控組件相較非受控組件能賦予調用方更多的定製化職能。這一思路與軟件開發中的有異曲同工之妙, 同時讓筆者受益匪淺的 也是類似的思想。

藉助受控組件的賦能, 以 Input 組件為例, 比如調用方可以更為自由地對值進行校驗限制, 又比如在值發生變更時執行一些額外邏輯。

// 組件提供方
function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />
}

// 調用方
function Demo() {
  const [value, setValue] = React.useState(1)
  return <Input value={value} onChange={e =>
    // 只支持數值的變更
    if (/\D/.test(e.target.value)) return
    setValue(e.target.value)}
  />
}

因此綜合基礎組件擴展性通用性的考慮, 受控組件的職能相較非受控組件更加寬泛, 建議優先使用受控組件來構建基礎組件。

反模式 —— 以非受控組件的使用方式調用受控組件

首先何謂反模式? 筆者將其總結為增大隱性 bug 出現概率的模式, 該模式是最佳實踐的對立經驗。如若使用了反模式就不得不花更多的精力去避免潛在 bug。官網對反模式也有很好的。

緣何上文提到以非受控組件的使用方式去調用受控組件是一種反模式? 觀察 Input 組件的第一行代碼, 其將 defaultValue 賦值給 value, 這種將 props 賦值給 state 的賦值行為在一定程度上會增加某些隱性 bug 的出現概率。

比如在切換導航欄的場景中, 恰巧兩個導航中傳進組件的 defaultValue 是相同的值, 在導航切換的過程中便會將導航一中的 Input 的狀態值帶到導航二中, 這顯然會讓使用方感到困惑。

// 組件提供方
function Input({ defaultValue }) {
  // 反模式
  const [value, setValue] = React.useState(defaultValue);
  React.useEffect(() => {
    setValue(defaultValue);
  }, [defaultValue]);
  return <input value={value} onChange={e => setValue(e.target.value)} />;
}

// 調用方
function Demo({ defaultValue }) {
  return <Input defaultValue={defaultValue} />;
}

function App() {
  const [tab, setTab] = React.useState(1);
  return (
    <>
      {tab === 1 ? <Demo defaultValue={1} /> : <Demo defaultValue={1} />}
      <button onClick={() => (tab === 1 ? setTab(2) : setTab(1))}>
        切換 Tab
      </button>
    </>
  );
}

如何避免使用該反模式同時有效解決問題呢? 官方提供了兩種較為優質的解法, 將其留給大家作為思考。

  1. 方法一: (更為推薦)
  2. 方法二:

歡迎關注

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

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

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

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