澳洲研究新燃煤電廠 引發環保團體批評

摘錄自2020年2月9日聯合新聞網報導

澳洲政府將撥款600萬澳幣(約400萬美元),給新電廠研究計畫,以降低電價並改善電網可靠性。但此研究的對象是燃煤電廠,因而引發環保人士批評,認為當局未努力對抗氣候變遷。

澳洲政府表示,將提供共計600萬澳幣供昆士蘭省的新發電計畫研究使用,其中400萬澳幣用於柯林斯維爾燃煤電廠的可行性研究,該電廠號稱「高效率、低排放」、發電量達1GW(10億瓦);另外200萬澳幣則撥給發電量1.5 GW的水力發電廠,以進行可行性的初步研究。

莫里森政府向來是燃煤產業的堅定擁護者,儘管這種燃料污染嚴重,反彈聲浪也日益增加,也不見政府立場改變。隨著澳洲野火從去年延燒至今,抨擊政府氣候變遷政策缺乏連貫性的力道也加強。乾淨能源專家荷姆斯說,澳洲政府的電廠投資計畫不切實際,當局只是為了自己的「意識形態」而浪費公帑。

燃煤仍占澳洲六成發電量,但幾座老舊電廠預定將於未來十年內退役。

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

北京公用充電樁數量今年將破萬 實現手機支付

據北京市科委消息,截至2015年年底,北京共建成公用充電樁5008根,2016年將再建5000根。

日前,“電動社區”行動計畫暨北京市充電設施公共服務管理平臺(e充網)啟動,將選擇500家社區率先實現電源條件到車位,並在無充電樁安裝條件社區率先投放500台移動充電車。

北京市“電動社區”行動計畫對於三類情況不同的社區給出了三種解決方案:對於有固定停車位元且具備電容量的社區,遴選500家,率先實現電源條件到車位;對於無固定停車位的社區,鼓勵在公共管理區域率先建設公用充電樁;在無充電樁安裝條件的社區,將投放500台移動充電車,方便車主預約充電車到車位充電,其投放範圍覆蓋北京16區中包括老舊社區、保障房社區、大型居住社區等各類社區200個。

公用充電樁將實現手機支付

據e充網工作人員表示,目前e充網已經實現了北京地區建設運營商全納入,全市所有公用充電樁的位置與導航資訊均收入到了APP之中。

此外,在充電樁國標符合性改造的過程中,統一支付結算(支持支付寶、微信、銀聯)、即時資料更新、充電樁預約等功能也會同步實施,即充電樁升級一批,其即時資料、統一支付結算等功能便實現一批,到今年6月底,電動汽車車主可以從“多卡不通用”的困境中解放出來,用手機實現線上查詢支付等諸多功能。

e充網工作人員介紹,目前北京已有604根快充樁(直流樁)實現了統一支付結算、即時資料更新的功能。

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

【其他文章推薦】

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

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

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

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

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

Spring Security登錄驗證流程源碼解析

一、登錄認證基於過濾器鏈

Spring Security的登錄驗證流程核心就是過濾器鏈。當一個請求到達時按照過濾器鏈的順序依次進行處理,通過所有過濾器鏈的驗證,就可以訪問API接口了。

SpringSecurity提供了多種登錄認證的方式,由多種Filter過濾器來實現,比如:

  • BasicAuthenticationFilter實現的是HttpBasic模式的登錄認證
  • UsernamePasswordAuthenticationFilter實現用戶名密碼的登錄認證
  • RememberMeAuthenticationFilter實現登錄認證的“記住我”的功能
  • SmsCodeAuthenticationFilter實現短信驗證碼登錄認證
  • SocialAuthenticationFilter實現社交媒體方式登錄認證的處理
  • Oauth2AuthenticationProcessingFilter和Oauth2ClientAuthenticationProcessingFilter實現Oauth2的鑒權方式

根據我們不同的需求實現及配置,不同的Filter會被加載到應用中。

二、結合源碼講解登錄驗證流程

我們就以用戶名、密碼登錄方式為例講解一下Spring Security的登錄認證流程。

2.1 UsernamePasswordAuthenticationFilter

該過濾器封裝用戶基本信息(用戶名、密碼),定義登錄表單數據接收相關的信息。如:

  • 默認的表單用戶名密碼input框name是username、password
  • 默認的處理登錄請求路徑是/login、使用POST方法

2.2 AbstractAuthenticationProcessingFilter的doFilter方法的驗證過程

UsernamePasswordAuthenticationFilter繼承自抽象類AbstractAuthenticationProcessingFilter,該抽象類定義了驗證成功與驗證失敗的處理方法。

2.3 驗證成功之後的Handler和驗證失敗之後的handler

也就是說當我們需要自定義驗證成功或失敗的處理方法時,要去實現AuthenticationSuccessHandler或AuthenticationfailureHandler接口

三、登錄驗證內部細節

3.1多種認證方式的管理 ProviderManager

ProviderManager用繼承於AuthenticationManager是登錄驗證的核心類。ProviderManager保管了多個AuthenticationProvider,用於不同類型的登錄驗證。比如:

  • RememberMeAuthenticationProvider定義了“記住我”功能的登錄驗證邏輯
  • DaoAuthenticationProvider加載數據庫用戶信息,進行用戶密碼的登錄驗證
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
    ……
    private List<AuthenticationProvider> providers;
    ……

下文是ProviderManager的核心源碼,遍歷不同登錄驗證的AuthenticationProvider,只有當這種方式被支持的時候,才執行具體的登錄驗證邏輯。

3.2 登錄認證接口 AuthenticationProvider

public interface AuthenticationProvider {
    Authentication authenticate(Authentication var1) throws AuthenticationException;

    boolean supports(Class<?> var1);
}

AuthenticationProvider的實現類定義了具體的登錄驗證邏輯

3.3 數據庫加載用戶信息 DaoAuthenticationProvider

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

從數據庫獲取用戶信息源碼

所以當我們需要加載用戶信息進行登錄驗證的時候,我們需要實現UserDetailsService接口,重寫loadUserByUsername方法,參數是用戶輸入的用戶名。返回值是UserDetails

期待您的關注

  • 博主最近新寫了一本書:
  • 本文轉載註明出處(必須帶連接,不能只轉文字):。

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

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

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

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

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

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

小白學 Python(23):Excel 基礎操作(上)

人生苦短,我選Python

前文傳送門

讀取 Excel

不知道各位同學有沒有見過有關 Python 操作 Excel 的廣告。小編是見過好多次的,還只需 ¥9.9 就能學習,今天小編就為大家帶來免費的 Python 操作 Excel 的入門教程。

仔細看,仔細學,本文價值 ¥9.9 哦~~~

這牛逼吹得我自己都有點臉紅。

既然要操作 Excel ,那我們就需要先建立一個 Excel 。

首先在 Excel 中創建 3 個 Sheet ,別跟我說不知道什麼是 Sheet ,可能你不適合看本篇內容。

測試使用 Excel 已經上傳至代碼倉庫,有需要的同學可以取用。

Excel 內容如下:

請先暫時忽略右下角的日期時間,這日期時間並無實際作用,僅用來演示使用。

這是一個 Sheet 的數據,同樣的 Sheet 存在 3 個。

可能各位同學看到這個 Excel 以後大致能猜到小編要幹啥了,對,沒錯,你猜對了,小編就是要算一下平均成績。

那麼用 Excel 自帶的公式來算平均成績不香么,非要用 Python 算,勞民傷財的。

Excel 自帶的函數確實強大,這個不得不服,但是,我如果要跨 Sheet 的操作呢?本文要玩的騷操作就是要跨 Sheet 計算平均成績。

首先,我們需要導入第三方模塊 xlrd ,因為是第三方的模塊,沒有安裝的同學需要先安裝。在命令行中輸入:

pip install xlrd

等待進度條走完就好了。

獲取 workbook:

首先,我們需要在代碼中打開我們剛才創建的 Excel :

workbook = xlrd.open_workbook('test.xlsx')

小編這裏為了方便,將 test.xlsx 和代碼放在同一目錄,實際在操作中需注意文件的路徑問題,不管是使用相對路徑還是絕對路徑,都要寫對。

Sheet 有關操作:

有關 Sheet 的操作有很多,我們列舉幾個常用的:

# 輸出所有 sheet 的名字
print(workbook.sheet_names())
# 獲取所有的 sheet
print(workbook.sheets())
# 根據索引獲取 sheet
print(workbook.sheet_by_index(1))
# 根據名字獲取 sheet
print(workbook.sheet_by_name('1班'))

輸出結果我這裏就不演示了,各位同學自己操作下就知道了:)

常用操作:

獲取行數和列數:

sheet1 = workbook.sheets()[0]
# 獲取行數
print(sheet1.nrows)
# 獲取列數
print(sheet1.ncols)

結果如下:

6
4

獲取整行和整列的數據(數據類型為列表):

# 獲取第 2 行內容
print(sheet1.row_values(1))
# 獲取第 3 列內容
print(sheet1.col_values(2))

結果如下:

['小明', 76.0, 85.0, 95.0, '']
['數學', 85.0, 58.0, 96.0, '', '']

獲取單元格的數據:

cell1 = sheet1.cell(1, 1).value
# 行索引
cell2 = sheet1.row(1)[1].value
cell3 = sheet1.cell(1, 2).value
# 列索引
cell4 = sheet1.col(2)[1].value

結果如下:

76.0 76.0 85.0 85.0

獲取日期類型數據:

date_value = xlrd.xldate_as_datetime(sheet1.cell_value(5, 3), workbook.datemode)
print(type(date_value), date_value)

結果如下:

<class 'datetime.datetime'> 2019-11-07 20:49:05

這裡是直接通過方法將數據轉成了 datetime 類型, xlrd 還提供了可以將數據轉成元組,然後再將元組轉成日期。

date_tulp = xlrd.xldate_as_tuple(sheet1.cell_value(5, 3), workbook.datemode)
print(type(date_tulp), date_tulp)
year, month, day, hour, minute, second = date_tulp
print(datetime.datetime(year, month, day, hour, minute, second))

結果如下:

<class 'tuple'> (2019, 11, 7, 20, 49, 5)
2019-11-07 20:49:05

今天的重頭戲是求平均數,但是我不想在文章里貼代碼了,只好請各位同學自己動下手咯~~~

當然,如果實在搞不定可以訪問代碼倉庫,具體的實現代碼小編還是會提交至代碼倉庫,不過小編還是希望各位同學能獨立完成作業~~

示例代碼

本系列的所有代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。

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

【其他文章推薦】

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

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

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

SSE圖像算法優化系列三十:GIMP中的Noise Reduction算法原理及快速實現。

  GIMP源代碼鏈接:

  GEGL相關代碼鏈接:

  最近因為要研究下色溫算法,順便下載了最新的GIMP軟件,色溫算法倒是找到了(有空單獨來講下),也順便看看GIMP都有些什麼更新,嗯,更新還是蠻多的,界面UI上有很多改動,有些已經改的面目全非了。隨便瞄了一下Enhance菜單,發現裏面有一個Nosie Reduction算法,試了下,還有點效果。於是在github上下載了GIMP的源代碼,可是在源代碼里搜索相關的關鍵詞確沒有發現任何的相關代碼,後來才發現很多東西都有個GEGL關鍵詞,結果一百度,原來他是一個單獨的軟件包,於是有下載了GEGL的源代碼,終於在gegl-master\operations\common\裏面看到了noise-reduction.c文件。

  其核心的代碼如下:

static void
noise_reduction (float *src_buf,     /* source buffer, one pixel to the left
                                        and up from the starting pixel */
                 int    src_stride,  /* stridewidth of buffer in pixels */
                 float *dst_buf,     /* destination buffer */
                 int    dst_width,   /* width to render */
                 int    dst_height,  /* height to render */
                 int    dst_stride)  /* stride of target buffer */
{
  int c;
  int x,y;
  int dst_offset;

#define NEIGHBOURS 8
#define AXES       (NEIGHBOURS/2)

#define POW2(a) ((a)*(a))
/* core code/formulas to be tweaked for the tuning the implementation */
#define GEN_METRIC(before, center, after) \
                   POW2((center) * 2 - (before) - (after))

/* Condition used to bail diffusion from a direction */
#define BAIL_CONDITION(new,original) ((new) > (original))

#define SYMMETRY(a)  (NEIGHBOURS - (a) - 1) /* point-symmetric neighbour pixel */

#define O(u,v) (((u)+((v) * src_stride)) * 4)
  int   offsets[NEIGHBOURS] = {  /* array of the relative distance i float
                                  * pointers to each of neighbours
                                  * in source buffer, allows quick referencing.
                                  */
              O( -1, -1), O(0, -1), O(1, -1),
              O( -1,  0),           O(1,  0),
              O( -1,  1), O(0, 1),  O(1,  1)};
#undef O

  dst_offset = 0;
  for (y=0; y<dst_height; y++)
    {
      float *center_pix = src_buf + ((y+1) * src_stride + 1) * 4;
      dst_offset = dst_stride * y;
      for (x=0; x<dst_width; x++)
        {
          for (c=0; c<3; c++) /* do each color component individually */
            {
              float  metric_reference[AXES];
              int    axis;
              int    direction;
              float  sum;
              int    count;

              for (axis = 0; axis < AXES; axis++)
                { /* initialize original metrics for the horizontal, vertical
                     and 2 diagonal metrics */
                  float *before_pix  = center_pix + offsets[axis];
                  float *after_pix   = center_pix + offsets[SYMMETRY(axis)];

                  metric_reference[axis] =
                    GEN_METRIC (before_pix[c], center_pix[c], after_pix[c]);
                }

              sum   = center_pix[c];
              count = 1;

              /* try smearing in data from all neighbours */
              for (direction = 0; direction < NEIGHBOURS; direction++)
                {
                  float *pix   = center_pix + offsets[direction];
                  float  value = pix[c] * 0.5 + center_pix[c] * 0.5;
                  int    axis;
                  int    valid;

                  /* check if the non-smoothing operating check is true if
                   * smearing from this direction for any of the axes */
                  valid = 1; /* assume it will be valid */
                  for (axis = 0; axis < AXES; axis++)
                    {
                      float *before_pix = center_pix + offsets[axis];
                      float *after_pix  = center_pix + offsets[SYMMETRY(axis)];
                      float  metric_new =
                             GEN_METRIC (before_pix[c], value, after_pix[c]);

                      if (BAIL_CONDITION(metric_new, metric_reference[axis]))
                        {
                          valid = 0; /* mark as not a valid smoothing, and .. */
                          break;     /* .. break out of loop */
                        }
                    }
                  if (valid) /* we were still smooth in all axes */
                    {        /* add up contribution to final result  */
                      sum += value;
                      count ++;
                    }
                }
              dst_buf[dst_offset*4+c] = sum / count;
            }
          dst_buf[dst_offset*4+3] = center_pix[3]; /* copy alpha unmodified */
          dst_offset++;
          center_pix += 4;
        }
    }
}

   這個代碼看上去比較混亂,沒辦法,大型軟件沒有哪一個代碼看上去能讓人省心的,而且也不怎麼講究效率,我測試了一個3K*2K的彩色圖,在GIMP里大概在4S左右處理完成,屬於很慢的了,看這個代碼,也知道大概有width * height * 3 * 8 * 4 * Iter個循環,計算量確實是相當的大。

  我試着嘗試優化這個算法。

  優化的第一步是弄明白算法的原理,在GIMP的UI界面上可當鼠標停留在Noise Reduction菜單上時,會出現Anisotroic smoothing operation字樣,所以初步分析他是屬於各項異性擴散類的算法。稍微分析下代碼,也確實是。明顯這屬於一個領域濾波器,對每一個像素,求取其3*3領域內的累加值,但是3*3領域的權重並不是平均分佈或者是高斯分佈,而是和領域的值有關的,如果領域的值是一個邊緣點,他將不參与到累加中,權重為0,否則權重為1。

  具體一點,對於領域里的任何一點,我們先求取其和中心點的平均值,對應 float value = pix[c] * 0.5 + center_pix[c] * 0.5; 這條語句,然後計算這個值在2個45度對角線及水平和垂直方向的梯度(4個梯度值)是否比中心點在四個方向的梯度都小,如果都小,說明這個領域點不屬於邊緣點,可以往這個方向擴散,把他計入到統計值中,如果有任何一個方向小了,則不參与最終的計算。

  上面的過程可以看成是標準的各項異性擴散的特殊在特殊處理,他具有各項異性擴散的特性,也具有一些特殊性。

  下一步,稍微分析下最簡單的優化方法。第一,我們知道,在大循環里一般不建議嵌套入小的循環,這樣是很低效的。我們觀察到上面代碼里的

      for (c=0; c<3; c++) /* do each color component individually */

  這個語句主要是為了方便表達3通道的處理的方便,但是其實三通道之間的處理時沒有任何聯繫的,對於這樣的算法,很明顯,我們可以一次性當然處理R G B R G B R G B ,而不需要像GIMP這個代碼這樣按照 RRR  GGG  BBB這樣的順序來寫,GIMP這種寫法浪費了很多CPU的CACHE,畢竟R和G和B在內存類分佈本來就是連續的。這樣就減少了一個小循環。

  第二個優化的點是,對於普通的圖像數據,我們可以考慮不用浮點數來處理,畢竟上述計算里只有*0.5這樣的浮點操作,我們考慮將原先的圖像數據放大一定的倍數,然後用整形來玩,在處理完后,在縮小到原來的範圍,比如使用short類型應該就足夠了,我把數據放大16倍或者32倍,甚至8倍應該都能獲得足夠的精度。

  第三個優化點,程序中是使用的Pow來判斷梯度的大小的,其實可以不用,直接使用絕對值的結果和Pow是完全一樣的,而絕對值的計算量比pow要小很多,對於整數則更為如此(還可以不考慮pow數據類型的改變,比如short的絕對值還是short類型,但是其pow可能就需要用int來表示了,這在SIMD優化會產生不同的結果)。

  第四個優化點是 for (axis = 0; axis < AXES; axis++)這個小循環我們應該把它直接展開。

  第五點,我們還可以考慮我在其他文章里提到的支持Inplace操作的方式,這樣noise_reduction這個函數的輸入和輸出就可以是同一個內存。

  第六點還有小點上的算法改進,比如一些中間計算沒必要重複進行,有些可以提到外部來等。

  綜合上面的描述,我整理除了一個優化的C語言版本的程序,如下所示:

void IM_AnisotropicDiffusion3X3(short *Src, short *Dest, int Width, int Height, int SplitPos, int Stride)
{
    int Channel = Stride / Width;

    short *RowCopy = (short *)malloc((Width + 2) * 3 * Channel * sizeof(short));
    short *First = RowCopy;
    short *Second = RowCopy + (Width + 2) * Channel;
    short *Third = RowCopy + (Width + 2) * 2 * Channel;
    memcpy(Second, Src, Channel * sizeof(short));
    memcpy(Second + Channel, Src, Width * Channel * sizeof(short));                                                    //    拷貝數據到中間位置
    memcpy(Second + (Width + 1) * Channel, Src + (Width - 1) * Channel, Channel * sizeof(short));

    memcpy(First, Second, (Width + 2) * Channel * sizeof(short));                                                    //    第一行和第二行一樣

    memcpy(Third, Src + Stride, Channel * sizeof(short));                                                            //    拷貝第二行數據
    memcpy(Third + Channel, Src + Stride, Width * Channel* sizeof(short));
    memcpy(Third + (Width + 1) * Channel, Src + Stride + (Width - 1) * Channel, Channel* sizeof(short));

    for (int Y = 0; Y < Height; Y++)
    {
        short *LinePD = Dest + Y * Stride;
        if (Y != 0)
        {
            short *Temp = First; First = Second; Second = Third; Third = Temp;
        }
        if (Y == Height - 1)
        {
            memcpy(Third, Second, (Width + 2) * Channel * sizeof(short));
        }
        else
        {
            memcpy(Third, Src + (Y + 1) * Stride, Channel * sizeof(short));
            memcpy(Third + Channel, Src + (Y + 1) * Stride, Width * Channel * sizeof(short));                            //    由於備份了前面一行的數據,這裏即使Src和Dest相同也是沒有問題的
            memcpy(Third + (Width + 1) * Channel, Src + (Y + 1) * Stride + (Width - 1) * Channel, Channel * sizeof(short));
        }
        for (int X = 0; X < SplitPos * Channel; X++)
        {
            short LT = First[X], T = First[X + Channel], RT = First[X + 2 * Channel];
            short L = Second[X], C = Second[X + Channel], R = Second[X + 2 * Channel];
            short LB = Third[X], B = Third[X + Channel], RB = Third[X + 2 * Channel];
            short LT_RB = LT + RB,    RT_LB = RT + LB;
            short T_B = T + B,        L_R = L + R,        C_C = C + C;
            short Dist1 = IM_Abs(C_C - LT_RB),        Dist2 = IM_Abs(C_C - T_B);
            short Dist3 = IM_Abs(C_C - RT_LB),        Dist4 = IM_Abs(C_C - L_R);
            
            int Sum = C_C, Amount = 2;

            short LT_C = LT + C;
            if ((IM_Abs(LT_C - LT_RB) < Dist1) && (IM_Abs(LT_C - T_B) < Dist2) && (IM_Abs(LT_C - RT_LB) < Dist3) && (IM_Abs(LT_C - L_R) < Dist4))
            {
                Sum += LT_C;
                Amount += 2;
            }
            short T_C = T + C;
            if ((IM_Abs(T_C - LT_RB) < Dist1) && (IM_Abs(T_C - T_B) < Dist2) && (IM_Abs(T_C - RT_LB) < Dist3) && (IM_Abs(T_C - L_R) < Dist4))
            {
                Sum += T_C;
                Amount += 2;
            }
            short RT_C = RT + C;
            if ((IM_Abs(RT_C - LT_RB) < Dist1) && (IM_Abs(RT_C - T_B) < Dist2) && (IM_Abs(RT_C - RT_LB) < Dist3) && (IM_Abs(RT_C - L_R) < Dist4))
            {
                Sum += RT_C;
                Amount += 2;
            }
            short L_C = L + C;
            if ((IM_Abs(L_C - LT_RB) < Dist1) && (IM_Abs(L_C - T_B) < Dist2) && (IM_Abs(L_C - RT_LB) < Dist3) && (IM_Abs(L_C - L_R) < Dist4))
            {
                Sum += L_C;
                Amount += 2;
            }
            short R_C = R + C;
            if ((IM_Abs(R_C - LT_RB) < Dist1) && (IM_Abs(R_C - T_B) < Dist2) && (IM_Abs(R_C - RT_LB) < Dist3) && (IM_Abs(R_C - L_R) < Dist4))
            {
                Sum += R_C;
                Amount += 2;
            }
            short LB_C = LB + C;
            if ((IM_Abs(LB_C - LT_RB) < Dist1) && (IM_Abs(LB_C - T_B) < Dist2) && (IM_Abs(LB_C - RT_LB) < Dist3) && (IM_Abs(LB_C - L_R) < Dist4))
            {
                Sum += LB_C;
                Amount += 2;
            }
            short B_C = B + C;
            if ((IM_Abs(B_C - LT_RB) < Dist1) && (IM_Abs(B_C - T_B) < Dist2) && (IM_Abs(B_C - RT_LB) < Dist3) && (IM_Abs(B_C - L_R) < Dist4))
            {
                Sum += B_C;
                Amount += 2;
            }
            short RB_C = RB + C;
            if ((IM_Abs(RB_C - LT_RB) < Dist1) && (IM_Abs(RB_C - T_B) < Dist2) && (IM_Abs(RB_C - RT_LB) < Dist3) && (IM_Abs(RB_C - L_R) < Dist4))
            {
                Sum += RB_C;
                Amount += 2;
            }
            LinePD[X] = Sum / Amount;
        }
    }
    free(RowCopy);
}

  調用函數

int IM_ReduceNoise(unsigned char *Src, unsigned char *Dest, int Width, int Height, int Stride, int SplitPos,  int Strength)
{
    int Channel = Stride / Width;
    if ((Src == NULL) || (Dest == NULL))                        return IM_STATUS_NULLREFRENCE;
    if ((Width <= 0) || (Height <= 0))                            return IM_STATUS_INVALIDPARAMETER;
    if ((Channel != 1) && (Channel != 3))                         return IM_STATUS_INVALIDPARAMETER;

    Strength = IM_ClampI(Strength, 1, 10);
    SplitPos = IM_ClampI(SplitPos, 0, Width);
    int Status = IM_STATUS_OK;
    short *Temp = (short *)malloc(Height * Stride * sizeof(short));
    if (Temp == NULL)    return IM_STATUS_OUTOFMEMORY;
    for (int Y = 0; Y < Height * Stride; Y++)
    {
        Temp[Y] = Src[Y] << 3;
    }
    for (int Y = 0; Y < Strength; Y++)
    {
        IM_AnisotropicDiffusion3X3(Temp, Temp, Width, Height, SplitPos, Stride);
    }
    for (int Y = 0; Y < Height * Stride; Y++)
    {
        Dest[Y] = Temp[Y] >> 3;
    }
    free(Temp);
    return IM_STATUS_OK;
}

  是不是看起來比上面的GIMP得要舒服些,而且中間也大概只要原始圖像2倍的一個臨時內存了。在速度和內存佔用方面都前進了很多。

  我測試前面提到的那副3K*2K的圖像,耗時要7S多,但是我測試表面GIMP用了多核的,如果論單核,我這裏的速度要比他快2倍多。

  很明顯,這個速度是不可以接受的,我們需要繼續優化。

      我還是老套路,使用SIMD指令做處理,看到上面的代碼,其實真的覺得好容易改成SIMD的。

     short LT_RB = LT + RB,    RT_LB = RT + LB;
     short T_B = T + B,        L_R = L + R,        C_C = C + C;
     short Dist1 = IM_Abs(C_C - LT_RB),        Dist2 = IM_Abs(C_C - T_B);
     short Dist3 = IM_Abs(C_C - RT_LB),        Dist4 = IM_Abs(C_C - L_R);
 
這些加減絕對值都有完全對應的SSE指令。 _mm_add_epi16、 _mm_sub_epi16、_mm_abs_epi16,基本上就是照着寫。
  稍微複雜一點就是這裏:
  if ((IM_Abs(LT_C - LT_RB) < Dist1) && (IM_Abs(LT_C - T_B) < Dist2) && (IM_Abs(LT_C - RT_LB) < Dist3) && (IM_Abs(LT_C - L_R) < Dist4))
   {
     Sum += LT_C;
    Amount += 2;
   }
  在C語言里,這裏判斷會進行短路計算,即如果前一個條件已經不滿足了,後續的計算就不會進行。但是在SIMD指令里,是沒有這樣的機制的。我們只能全部計算,然後在通過某一種條件組合。
  在合理,要實現符合條件就進行累加,不符合條件就不做處理的需求,我們需要稍作修改,即不符合條件不是不做處理,而是加0,加0對結果沒有影響的。主要藉助下面的_mm_blendv_epi8來實現。
    __m128i LT_C = _mm_add_epi16(LT, C);
    Flag1 = _mm_cmplt_epi16(_mm_abs_epi16(_mm_sub_epi16(LT_C, LT_RB)), Dist1);        //    只能全部都計算,但還是能提速
    Flag2 = _mm_cmplt_epi16(_mm_abs_epi16(_mm_sub_epi16(LT_C, T_B)), Dist2);
    Flag3 = _mm_cmplt_epi16(_mm_abs_epi16(_mm_sub_epi16(LT_C, RT_LB)), Dist3);
    Flag4 = _mm_cmplt_epi16(_mm_abs_epi16(_mm_sub_epi16(LT_C, L_R)), Dist4);
    Flag = _mm_and_si128(_mm_and_si128(Flag1, Flag2), _mm_and_si128(Flag3, Flag4));
    Sum = _mm_adds_epu16(Sum, _mm_blendv_epi8(Zero, LT_C, Flag));
    Amount = _mm_adds_epu16(Amount, _mm_blendv_epi8(Zero, Two, Flag));

  注意到我們這裏用到了_mm_adds_epu16,無符號的16位加法,這是因為我需要盡量的提速,因此需要減少類型轉換的次數。同時,我們看到在統計累加值時,我們並沒有求平均值,而是直接用的累加值,這樣理論上最大的累加值就是 255 * n * (8 + 1) * 2 < 65535, 這樣n最大能取15,但是15不是個好數據,在放大和縮小都不能用移位來實現,所以我最後取得放大係數為8。

  另外,在最後還有個16位的整數的除法問題,這個沒有辦法,SSE指令沒有提供整數的除法計算方法,還只能轉換到浮點后,再次轉換回來。

  這樣用SSE處理后,還是同一幅測試圖像,在同一台PC上速度能提升到400ms(4次迭代),比之前的普通的C語言提高了約17倍的速度。

  在現代CPU中,具有AVX2指令集已經是很普遍的了,單AVX2能同時處理256字節的數據,比SSE還要多一倍,我也常使用AVX2進行優化處理,速度能達到250ms,相當於普通C語言的28倍之多(但是AVX編程里有很多坑,這些坑都拜AVX不是完全的按照SSE的線性擴展導致的,這個後續有時間我單獨提出)。

  經過測試,1080P的圖像使用4次迭代大約需要80ms,3次迭代55ms,2次迭代月40ms,也就是說前面的一些方法和縮小所使用的時間幾乎可以忽略。

  選了幾幅有特點的圖進行了去燥測試,其中分界線左側的位處理的效果,右側為未處理的。

 

  但是,這個算法也還是不是很好,他對於圖像容易出現輕微的油畫效果,對於一些細節特別豐富的圖像非常明顯,比如下圖:

  這個應該是不太可以接受的,也許可以通過修改部分權重的規則來改變這個現象。這個屬於後期研究的問題了。

     另外,在GIMP里也提供了這個算法的OPENCL實現,有興趣的可以源代碼里找一找,不曉得速度怎麼樣。

  本文Demo下載地址:  ,見其中的Denoise -> Anisotroic Diffusion 菜單。

  寫博不易,歡迎土豪打賞讚助。

 

 

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

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

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

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

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

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

系統分析師-軟件水平考試(高級)-開篇

系統分析師-軟件水平考試(高級)-開篇

前言

時隔一年,我開始了系統分析師的博客寫作。回過頭翻看一下,一年前的系統架構設計師系列的第一篇博客-需求理論,還是比較有感觸的。

其實系統分析師的考試早在上邊年五月份就參与了,也在六月份就知道自己通過了考試。但是一方面系統分析師與系統架構設計師有很多內容上的重複,另一方面自己確實工作也比較忙,所以相關的博客就擱置下來了。

正好最近有點空閑時間,正好一方面整理所學,一方面輸出一些博客,幫助大家。

分析師與架構師

首先,就是探討一下,系統分析師與系統架構設計師的關聯與區別。

兩者都是軟件考試的高級考試科目,並且也是相似對最高的兩門高級科目。畢竟早期軟考只有系統分析師的考試,而系統架構設計師是由於系統架構設計內容不斷增多,然後分離出來單獨成為一個科目的。

很多朋友都無法把握住兩門考試科目的區別,導致學習無法集中注意力,從而造成考試失利。

考試角度

首先從考試角度來說,系統分析師中有關架構的部分,分值比較低,可以說幾乎與企業信息化等章節一樣,就是個普通公民,不再享受系統架構設計師考試中一等公民的待遇了。其次,系統分析師由於在架構方面的分值大幅下降,所以提高了所有章節的分值。簡單說,就是所有章節的考試內容變多了。雖然深度不再深挖,但是考試範圍的擴大,導致考生覺得系統分析師內容太過繁雜,準備困難,難以把握重點。

那麼,分析師有沒有類似架構師的重點呢?答案是有的。從考試的分值散布(客觀,案例,論文綜合起來看),以及考試名稱——系統分析師,可以知道重點在分析。就像系統架構師的重心在架構,高項的重心在管理,分析師的重心在分析。當然了,由於系統分析師的特殊性(所有高級科目的源頭),所以它的重心不會如架構師,管理師那樣突出。

那麼落在考試章節中,分析又落實在哪裡呢?那就是系統規劃,需求分析,以及一些零散的涉及分析的內容。當然,如果你是第一次參与高級考試,可千萬別只看這兩個章節啊。

現實角度

老規矩,從考試的角度分析后,我們來從現實角度分析一下。當公司規模不大的時候,公司技術方面往往就一個技術部。技術部會有一個負責人,他會負責所有技術相關的問題,包括但不限於:

  • 技術顧問:負責解答公司高層對技術的疑惑
  • 技術評估:參与公司項目,產品的技術評估
  • 技術規劃:為公司的戰略目標,提供技術方面的長遠規劃
  • 技術管理:為領導的技術部門進行有效管理
  • 技術支持:為領導的項目提供技術的直接幫助

公司規模不大的時候(百人以內,技術部門二十人以內),負責人尚且還能支撐得住,能夠在各方,各個工作間周轉開。不要問我怎麼知道的,問就是我在上家公司就是做這些的。

但是隨着公司規模增大,技術部門的人數增長。技術負責就不可能面面俱到了(某些牛人,就算了,咱只說正常情況)。

到了這個時候,原有技術負責的工作必須進行拆分。在中型公司,比較常見的是採用矩陣型的組織結構,原技術負責的職責拆分為:

  • 技術總監:負責技術顧問,技術規劃
  • 項目經理:負責項目管理工作
  • 技術負責:負責單個項目的技術支持,配合項目經理與技術總監,完成技術評估,配合技術總監完成技術規劃的落地。

(這其中的需求,往往是三方的協調,妥協的一個結果。如果不懂得這句話,可以等到我開啟項目管理的分支,再細談。或者私聊我)

不要問我怎麼知道的,問就是因為年中有一個以前的上司來挖我的時候,和我提到了他們公司的情況。

可能你們要說,還是沒有看到系統分析師啊?別急,馬上就到了。

隨着項目規模的擴大,項目內的技術負責壓力就比較大了。一方面需要技術上司,業務方,項目經理打交道,了解具體需求,進而進行分析,另一方面還需要進行項目信息系統的架構設計,搭建,為下屬提供技術支持。所以,部分大型公司就再次將技術負責拆分為業務分析師與技術架構師,也就是大家說的BA和架構師。不要問我怎麼知道的,問就是這個月,打電話挖我的公司就有這麼做。當然,也有人注意到,需求這個東西不是應該交由項目經理處理嘛?怎麼說呢?一方面,有些需求只有技術人員才有那個敏感性,另一方面,項目經理雖然也有獲取需求這一過程,但並不表示只靠項目經理自己去獲取,更多的是需要依靠具體的人落實,後者具體的人配合落實。項目經理本身更多是一個協調整合的人員,而不一定就是具體落實的人。

學習必要性

可能有些朋友就要問了,大型公司才用到,那是不是對於很多人來說,這個考試的學習就沒有意義了。

當然不是。

首先,即使是在中小公司,分析師的學習會補全架構師在業務方面,商業層面的不足。在一家中小公司,一個幾乎只會談論技術的(雖然有着非常高超的架構水平,但不是每個公司都有“伯樂”的)與一個可以談論公司業務,可以為公司戰略發展提出一個考慮了商業內涵的技術方案的,相信後者會更得Boss的歡心。

其次,不想當將軍的士兵不是好士兵。不想去大公司露一手的,不是好員工。人嘛,總是要有一顆上進的心。

最後,我們需要提升自己視野,如果只局限於技術的維度,很容易把自己的職業道路走窄了。舉個例子,馬雲評價行癲,不僅有足夠的技術,更有着敏銳的商業視野。後面的故事,大家也都知道了,行癲上位(甚至現有的公司紛紛提出公司組成要有八成的技術人員,也不知道有沒有這方面的原因。囧)。

學習困難性

分析師學習難不難?

從數據角度。系統架構設計師的考試就比較困難了,其通過率接近8%,而分析師的通過率就只有系統架構設計師的一半不到,其通過率約為3%-4%。

從內容角度。套用一位老師說的話,從內容的深度而言,分析師的內容深度與系統架構設計師差不多。但是內容的量級上,分析師的內容量級比系統架構師要多(大概1.5倍吧,但是如果從架構師轉過來的話,只需要再學習0.7左右的內容)。

從抽象角度。對於有開發經驗的人而言,架構師中提到的技術,以及架構思想,起碼在經手的項目中能夠比較直觀的感受到。而分析師提到的系統規劃,需求分析等內容就不是每個開發人員能經手到的了。當然,對於沒有開發經驗的,那麼兩者幾乎是沒有什麼差別的。

XMIND

給出一個XMIND,讓大家比較直觀地感受到系統分析師的知識體系。

學習方法

那麼有沒有什麼辦法可以提高學習效率呢?

當然是有的。雖然我在架構師考試博客中推薦了許多書籍,但是分析師的書籍真的幾乎沒有,所以就不推薦了(畢竟也有一些人認為沒有時間看那麼多的書籍)。

說一下我的學習方法:

  • 首先,看一下教材的目錄,了解往年考試情況與分值分佈情況。然後有目的性地快速看一遍教材,不求甚解,只求留個印象。
  • 其次,配合XMIND,寫下各個章節的重點內容,從而建立知識體系(我十分看重建立知識體系,包括面試別人的時候)。
  • 然後,配合XMIND,按照重要程度,去細看教材。不大清楚的地方,還會查閱資料,詢問群友什麼的。
  • 最後,就是做題啦,每個章節學習完,都會做章節練習,判斷自己對這一章節的認識,並了解題型。另外學完所有章節(起碼是自己認為應該學習的章節)后,還會做模擬題(盡量還原出考場的感覺)。最重要的,別忘了錯題集,真的有用的。

總結

如果你想要參加考試,第一件事情就是需要明確自己是為了知識而來,還是為了考試而來,抑或是兩者都有的。

另外,我這邊確實有一個關於系統架構師/分析師的群,但是是邀請制的,也就是說給你群號也沒用。如果有參与考試的想法,可以私信@我。

最後,只想說一下,軟考高級是個好東西,但是也不可能讓你立馬上天的。它只是一個加速器,一個倍增器。就像架構師的考試,給了我一個很好的知識體系,雖然非常空蕩蕩的,但是我可以不斷向其中填充具體的技術。目測架構師考試的紅利,我至少還可以吃個三年。至於後續的分析師與管理師就更不用說了。最重要的是提供了非常好的視野,而視野這個東西,無法直觀地帶來薪水,職位的提升。但是這個東西的好處真的很多,關鍵其它途徑很難如此快速地獲得它。

最後,希望我的博客可以為大家提供幫助。謝謝。

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

擬砍伐森林建廠 Tesla歐洲「超級工廠」被叫停

摘錄自2020年2月17日星島日報報導

全球近年多現極端天氣,多國環保組織遞交請願,要求政府重視環保議題。美國最大電動車公司特斯拉(Tesla)早前計劃砍伐德國柏林的一處森林地建廠,事件遭到當地居民抗議後。當地法院昨(16日)表示,已應環保組織請求作出裁決,要求Tesla暫停在當地建廠的砍伐森林前期工程。

Tesla行政總監馬斯克去年11月宣布,將首家歐洲工廠落戶於柏林近郊的勃蘭登堡州,其後獲環境部許可,砍伐在選址區域內一片面積約92公頃的森林。不過此舉引來當地環保組織「綠色聯邦」不滿,擔憂工廠會威脅當地野生動物和水源,並向當地行政法院提出申請,要求緊急停止砍伐,惟被駁回。

最後當地高等行政法院推翻決定,同意要求特斯拉暫時停止砍伐。
 

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

【其他文章推薦】

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

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

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

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

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

東非蝗災肆虐 沙漠蝗蟲大舉攻進南蘇丹

摘錄自2020年2月19日中央社報導

南蘇丹農業部長尼克瓦克今(18日)表示,肆虐東非農作物和牧場的蝗蟲大軍,已經抵達飽受飢荒和多年內戰衝擊的南蘇丹。聯合國表示,沙漠蝗蟲一天可移動達150公里,且能吃掉與自己體重相差無幾的食物。

聯合國糧農組織(FAO)駐南蘇丹代表馬洛(Meshack Malo)說,這些蝗蟲已經成熟,正在尋找繁衍地點,而這將成為下一波嚴重災情的基礎。馬洛說,由於朝蟲卵噴藥恐汙染土壤,專家小組打算在牠們產卵的地方做記號,14天內再回頭消滅這些幼蟲。

石油資源豐饒的南蘇丹正從五年內戰逐步復甦,內戰導致這個國家的部分地區在2017年陷入飢荒並迫使1/4人口逃離家園。世界糧食計劃署(WFP)去年12月說,在洪災影響近100萬人後,糧食安全前景令人擔憂。

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

【其他文章推薦】

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

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

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

南投搬家前需注意的眉眉角角,別等搬了再說!

containerd 與安全沙箱的 Kubernetes 初體驗

作者 | 易立  阿里雲資深技術專家

containerd 是一個開源的行業標準容器運行時,關注於簡單、穩定和可移植,同時支持 Linux 和 Windows。

  • 2016 年 12 月 14 日,Docker 公司宣布將 Docker Engine 的核心組件 containerd 捐贈到一個新的開源社區獨立發展和運營。阿里雲、AWS、 Google、IBM 和 Microsoft 作為初始成員,共同建設 containerd 社區;

  • 2017 年 3 月,Docker 將 containerd 捐獻給 CNCF(雲原生計算基金會)。containerd 得到了快速的發展和廣泛的支持;

  • Docker 引擎已經將 containerd 作為容器生命周期管理的基礎,Kubernetes 也在 2018 年 5 月,正式支持 containerd 作為容器運行時管理器;

  • 2019 年 2 月,CNCF 宣布 containerd 畢業,成為生產可用的項目。

containerd 從 1.1 版本開始就已經內置了 Container Runtime Interface (CRI) 支持,進一步簡化了對 Kubernetes 的支持。其架構圖如下:

在 Kubernetes 場景下,containerd 與完整 Docker Engine 相比,具有更少的資源佔用和更快的啟動速度。

圖片來源:

紅帽主導的 cri-o 是與 containerd 競爭的容器運行時管理項目。containerd 與 cri-o 項目相比,在性能上具備優勢,在社區支持上也更加廣泛。

圖片來源:

更重要的是 containerd 提供了靈活的擴展機制,支持各種符合 OCI(Open Container Initiative)的容器運行時實現,比如 runc 容器(也是熟知的 Docker 容器)、KataContainer、gVisor 和 Firecraker 等安全沙箱容器。

在 Kubernetes 環境中,可以用不同的 API 和命令行工具來管理容器 / Pod、鏡像等概念。為了便於大家理解,我們可以用下圖說明如何利用不同層次的 API 和 CLI 管理容器生命周期管理。

  • Kubectl:是集群層面的命令行工具,支持 Kubernetes 的基本概念
  • :是針對節點上 CRI 的命令行工具
  • :是針對 containerd 的命令行工具

體驗

Minikube 是體驗 containerd 作為 Kubernetes 容器運行時的最簡單方式,我們下面將其作為 Kubernetes 容器運行時,並支持 runc 和 gvisor 兩種不同的實現。

早期由於網絡訪問原因,很多朋友無法直接使用官方 Minikube 進行實驗。在最新的 Minikube 1.5 版本中,已經提供了完善的配置化方式,可以幫助大家利用阿里雲的鏡像地址來獲取所需 Docker 鏡像和配置,同時支持 Docker/Containerd 等不同容器運行時。我們一個 Minikube 虛擬機環境,注意需要指明 --container-runtime=containerd 參數設置 containerd 作為容器運行時。同時 registry-mirror 也要替換成自己的阿里雲鏡像加速地址。

$ minikube start --image-mirror-country cn \
    --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.5.0.iso \
    --registry-mirror=https://XXX.mirror.aliyuncs.com \
    --container-runtime=containerd
  Darwin 10.14.6 上的 minikube v1.5.0
  Automatically selected the 'hyperkit' driver (alternates: [virtualbox])
️  您所在位置的已知存儲庫都無法訪問。正在將 registry.cn-hangzhou.aliyuncs.com/google_containers 用作後備存儲庫。
  正在創建 hyperkit 虛擬機(CPUs=2,Memory=2000MB, Disk=20000MB)...
️  VM is unable to connect to the selected image repository: command failed: curl -sS https://k8s.gcr.io/
stdout:
stderr: curl: (7) Failed to connect to k8s.gcr.io port 443: Connection timed out
: Process exited with status 7
  正在 containerd 1.2.8 中準備 Kubernetes v1.16.2…
  拉取鏡像 ...
  正在啟動 Kubernetes ...
⌛  Waiting for: apiserver etcd scheduler controller
  完成!kubectl 已經配置至 "minikube"
$ minikube dashboard
  Verifying dashboard health ...
  Launching proxy ...
  Verifying proxy health ...
  Opening http://127.0.0.1:54438/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...

部署測試應用

我們通過 Pod 部署一個 nginx 應用:

$ cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
$ kubectl apply -f nginx.yaml
pod/nginx created
$ kubectl exec nginx -- uname -a
Linux nginx 4.19.76 #1 SMP Fri Oct 25 16:07:41 PDT 2019 x86_64 GNU/Linux

然後,我們開啟 minikube 對 gvisor 支持:

$ minikube addons enable gvisor
  gvisor was successfully enabled
$ kubectl get pod,runtimeclass gvisor -n kube-system
NAME         READY   STATUS    RESTARTS   AGE
pod/gvisor   1/1     Running   0          60m
NAME                              CREATED AT
runtimeclass.node.k8s.io/gvisor   2019-10-27T01:40:45Z
$ kubectl get runtimeClass
NAME     CREATED AT
gvisor   2019-10-27T01:40:45Z

當 gvisor pod 進入 Running 狀態的時候,可以部署 gvisor 測試應用。

我們可以看到 K8s 集群中已經註冊了一個 gvisor 的“runtimeClassName”。之後,開發者可以通過在 Pod 聲明中的 “runtimeClassName” 來選擇不同類型的容器運行時實現。比如,如下我們創建一個運行在 gvisor 沙箱容器中的 nginx 應用。

$ cat nginx-untrusted.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-untrusted
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx
$ kubectl apply -f nginx-untrusted.yaml
pod/nginx-untrusted created
$ kubectl exec nginx-untrusted -- uname -a
Linux nginx-untrusted 4.4 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 GNU/Linux

我們可以清楚地發現:由於基於 runc 的容器與宿主機共享操作系統內核,runc 容器中查看到的 OS 內核版本與 Minikube 宿主機 OS 內核版本相同;而 gvisor 的 runsc 容器採用了獨立內核,它和 Minikube 宿主機 OS 內核版本不同。

正是因為每個沙箱容器擁有獨立的內核,減小了安全攻擊面,具備更好的安全隔離特性。適合隔離不可信的應用,或者多租戶場景。注意:gvisor 在 minikube 中,通過 ptrace 對內核調用進行攔截,其性能損耗較大,此外 gvisor 的兼容性還有待增強。

使用 ctl 和 crictl 工具

我們現在可以進入進入 Minikube 虛擬機:

$ minikube ssh

containerd 支持通過名空間對容器資源進行隔離,查看現有 containerd 名空間:

$ sudo ctr namespaces ls
NAME   LABELS
k8s.io
# 列出所有容器鏡像
$ sudo ctr --namespace=k8s.io images ls
...
# 列出所有容器列表
$ sudo ctr --namespace=k8s.io containers ls

在 Kubernetes 環境更加簡單的方式是利用 crictl 對 pods 進行操作。

# 查看pod列表
$ sudo crictl pods
POD ID              CREATED             STATE               NAME                                         NAMESPACE              ATTEMPT
78bd560a70327       3 hours ago         Ready               nginx-untrusted                              default                0
94817393744fd       3 hours ago         Ready               nginx                                        default                0
...
# 查看名稱包含nginx的pod的詳細信息
$ sudo crictl pods --name nginx -v
ID: 78bd560a70327f14077c441aa40da7e7ad52835100795a0fa9e5668f41760288
Name: nginx-untrusted
UID: dda218b1-d72e-4028-909d-55674fd99ea0
Namespace: default
Status: Ready
Created: 2019-10-27 02:40:02.660884453 +0000 UTC
Labels:
    io.kubernetes.pod.name -> nginx-untrusted
    io.kubernetes.pod.namespace -> default
    io.kubernetes.pod.uid -> dda218b1-d72e-4028-909d-55674fd99ea0
Annotations:
    kubectl.kubernetes.io/last-applied-configuration -> {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx-untrusted","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx"}],"runtimeClassName":"gvisor"}}
    kubernetes.io/config.seen -> 2019-10-27T02:40:00.675588392Z
    kubernetes.io/config.source -> api
ID: 94817393744fd18b72212a00132a61c6cc08e031afe7b5295edafd3518032f9f
Name: nginx
UID: bfcf51de-c921-4a9a-a60a-09faab1906c4
Namespace: default
Status: Ready
Created: 2019-10-27 02:38:19.724289298 +0000 UTC
Labels:
    io.kubernetes.pod.name -> nginx
    io.kubernetes.pod.namespace -> default
    io.kubernetes.pod.uid -> bfcf51de-c921-4a9a-a60a-09faab1906c4
Annotations:
    kubectl.kubernetes.io/last-applied-configuration -> {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx"}]}}
    kubernetes.io/config.seen -> 2019-10-27T02:38:18.206096389Z
    kubernetes.io/config.source -> api

containerd 與 Docker 的關係

很多同學都關心 containerd 與 Docker 的關係,以及是否 containerd 可以取代 Docker?

containerd 已經成為容器運行時的主流實現,也得到了 Docker 社區和 Kubernetes 社區的大力支持。Docker Engine 底層的容器生命周期管理也是基於 containerd 實現。

但是 Docker Engine 包含了更多的開發者工具鏈,比如鏡像構建。也包含了 Docker 自己的日誌、存儲、網絡、Swarm 編排等能力。此外,絕大多數容器生態廠商,如安全、監控、開發等對 Docker Engine 的支持比較完善,對 containerd 的支持也在逐漸補齊。

所以在 Kubernetes 運行時環境,對安全和效率和定製化更加關注的用戶可以選擇 containerd 作為容器運行時環境;對於大多數開發者,繼續使用 Docker Engine 作為容器運行時也是一個不錯的選擇。

阿里雲容器服務對 containerd 的支持

在阿里雲 Kubernetes 服務 ACK,我們已經採用 containerd 作為容器運行時管理,來支撐安全沙箱容器和 runc 容器的混合部署。在現有產品中,我們和阿里雲操作系統團隊、螞蟻金服一起支持了基於輕量虛擬化的 runV 沙箱容器,4Q 也將和操作系統團隊、安全團隊合作發布基於 Intel SGX 的可信加密沙箱容器。

具體產品信息可以參考。

Serverless Kubernetes(ASK)中,我們也利用 containerd 靈活的插件機制定製和剪裁了面向 nodeless 環境的容器運行時實現。

“ 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。”

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

特斯拉Model X中國售價96萬元起 Q2開始交付

2月1日,特斯拉公司宣佈將在中國市場首次推出Model X頂級限量 Signature Red版P90D(售價人民幣147.95萬元), 同時公佈目前在中國市場推出的Model X 標準版90D的官方價格區間(人民幣96.1-117.18萬元),並開始電話邀請預定Model X的消費者進行車輛選配,新車預計將於二季度開始在中國交付。

特斯拉目前在中國推出的Model X 90D擁有90千瓦時(kWh)的電池容量,續航里程高達470公里,零到百公里加速5.0秒,最高時速達到250公里/小時。Model X在中國的官方價格一直備受關注。得益於業內獨創的“官網電商+線下體驗店”的直營模式,特斯拉得以做到全球公平、透明定價。本次公佈的Model X 90D在中國的定價(人民幣96.1-117.18萬元)繼續秉持了這一原則,即只在美國本土售價的基礎上增加了關稅和運輸成本。消費者可以透明、自主得通過特斯拉官網定制和下單。

頂級限量Signature版是特斯拉在第一代超級跑車Roadster、第二代豪華轎跑車Model S的首發階段慣例推出的限量產品,車身飾有“Signature”字樣,可謂“頂配中的頂配”。本次在中國推出的Model X頂級限量Signature Red版P90D,其所擁有的名為“Signature Red”的紅色區別於所有其他量產的特斯拉車輛。當它開啟Ludicrous狂暴模式時,百公里加速僅需3.4秒,續航里程高達450公里,並配備主動擾流板和特斯拉紅色制動卡鉗等。


特斯拉頂配限量版“Signature Red” Model X

駕駛過程中,Model X的主動安全防護功能通過雷達和聲納系統即時監視路面情況,並主動向駕駛者提供回饋,最大幅度避免事故發生。獨特的車身結構能夠大幅度降低重心,與同類SUV相比,降低了50%的側翻風險。在NHTSA(美國國家公路交通安全管理局)的所有安全測試項目中,Model X都獲得了5星級評價。作為智慧SUV的代表,Model X最新的空中升級(OTA)7.1系統,擁有業界領先的自動駕駛(Autopilot)、自動泊車、召喚(Summon)等功能,讓駕車不再是一件麻煩的事情,而且該系統還在不斷前行。

Model X獨有的鷹翼門採用碳纖維雙鉸鏈結構,在傳統鷗翼門的設計之上,進一步提高承壓性及整車密封性。超聲波感應器智慧探測車身周圍的空間,以判斷車門是否能夠安全開啟。車門全部開啟只需要6-7秒,僅佔用30釐米的側方空間。全景擋風玻璃將前擋風玻璃和天窗連在一起,是目前轎車上安裝的最大單塊玻璃,給予使用者更加開闊的視野,優化的防曬隔熱玻璃膜全面提高安全係數。

7座Model X採用2+3+2的佈局,並且每個座位都採用獨立座椅,滿足全家的出行需求。此外還擁有豐富、超大的儲物空間。行李可以輕鬆置於Model X的前備箱、後備箱以及座椅下方。第三排座椅放倒之後,Model X的後備箱可輕鬆擺放高爾夫球包、折疊式兒童手推車、自行車、滑雪手杖及滑雪板等大型裝備。如果加裝車尾懸掛支架,Model X還可以攜帶更多行李。

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!