1. 程式人生 > >4個你未必知道的記憶體小知識

4個你未必知道的記憶體小知識

除了CPU,記憶體大概是最重要的計算資源了。基本成為分散式系統標配的快取中介軟體、高效能的資料處理系統及當前流行的大資料平臺,都離不開對計算機記憶體的深入理解與巧妙使用。本文將探索這個讓人感到熟悉又複雜的領域。

  1. 複雜的CPU與單純的記憶體
  2. 多核CPU與記憶體共享的問題
  3. 著名的Cache偽共享問題
  4. 深入理解不一致性記憶體

1 複雜的CPU與單純的記憶體

  首先,我們澄清幾個容易讓人混淆的CPU術語。

  • Socket或者Processor:指一個物理CPU晶片,盒裝的或者散裝的,上面有很多針腳,直接安裝在主機板上。
  • Core:指Socket裡封裝的一個CPU核心,每個Core都是完全獨立的計算單元,我們平時說的4核心CPU,就是指一個Socket(Processor)裡封裝了4個Core。
  • HT超執行緒:目前Intel與AMD的Processor大多支援在一個Core裡並行執行兩個執行緒,此時在作業系統看來就相當於兩個邏輯CPU(Logical
    Processor),在大多數情況下,我們在程式裡提到CPU這個概念時,就是指一個Logical Processor。

然後,我們先從第1個非常簡單的問題開始:CPU可以直接操作記憶體嗎?可能99%的程式設計師會不假思索地回答:“肯定的,不然程式怎麼跑。”如果理性地分析一下,你會發現這個回答有問題:CPU與記憶體條是獨立的兩個硬體,而且CPU上也沒有插槽和連線可以讓記憶體條掛上去,也就是說,CPU並不能直接訪問記憶體條,而是要通過主機板上的其他硬體(介面)來間接訪問記憶體條。
  第2個問題:CPU的運算速度與記憶體條的訪問速度之間的差距究竟有多大?這個差距跟王健林“先掙它個一個億的”小目標和“普通人有車有房”的巨集大目標之間的差距相比,是更大還是更小呢?答案是“差不多”。通常來說,CPU的運算速度與記憶體訪問速度之間的差距不過是100倍,假如有100萬元人民幣就可以有房(貸)有車(貸)了,那麼其100倍剛好是一億元人民幣。
  既然CPU的速度與記憶體的速度還是存在高達兩個數量級的巨大鴻溝,所以它們註定不能“幸福地在一起”,於是CPU的親密伴侶Cache閃亮登場。與來自DRAM家族的記憶體(Memory)出身不同,Cache來自SRAM家族。DRAM與SRAM最簡單的區別是後者特別快,容量特別小,電路結構非常複雜,造價特別高。
  造成Cache與記憶體之間巨大效能差距的主要原因是工作原理和結構不同,如下所述。

  • DRAM儲存一位資料只需要一個電容加一個電晶體,SRAM則需要6個電晶體。由於DRAM的資料其實是儲存在電容裡的,所以每次讀寫過程中的充放電環節也導致了DRAM讀寫資料有一個延遲的問題,這個延遲通常為十幾到幾十ns。
  • 記憶體可以看作一個二維陣列,每個儲存單元都有其行地址和列地址。由於SRAM的容量很小,所以儲存單元的地址(行與列)比較短,可以一次性傳輸到SRAM中;而DRAM則需要分別傳送行與列的地址。
  • SRAM的頻率基本與CPU的頻率保持一致;而DRAM的頻率直到DDR4以後才開始接近CPU的頻率。

Cache是被整合到CPU內部的一個儲存單元,一級Cache(L1 Cache)通常只有32~64KB的容量,這個容量遠遠不能滿足CPU大量、高速存取的需求。此外,由於儲存效能的大幅提升往往伴隨著價格的同步飆升,所以出於對整體成本的控制,現實中往往採用金字塔形的多級Cache體系來實現最佳快取效果,於是出現了二級Cache(L2 Cache)及三級Cache(L3 Cache),每一級Cache都犧牲了部分效能指標來換取更大的容量,目的是快取更多的熱點資料。以Intel家族Intel Sandy Bridge架構的CPU為例,其L1 Cache容量為64KB,訪問速度為1ns左右;L2 Cache容量擴大4倍,達到256KB,訪問速度則降低到3ns左右;L3 Cache的容量則擴大512倍,達到32MB,訪問速度也下降到12ns左右,即使如此,也比訪問主存的100ns(40ns+65ns)快一個數量級。此外,L3 Cache是被一個Socket上的所有CPU Core共享的,其實最早的L3 Cache被應用在AMD釋出的K6-III處理器上,當時的L3 Cache受限於製造工藝,並沒有被整合到CPU內部,而是整合在主機板上。
  下面給出了Intel Sandy Bridge CPU的架構圖,我們可以看出,CPU如果要訪問記憶體中的資料,則要經過L1、L2與L3這三道關卡後才能抵達目的地,這個過程並不是“皇上”(CPU)親自出馬,而是交由3個級別的貴妃(Cache)們層層轉發“聖旨”(記憶體指令),最終抵達“後宮”(記憶體)。
        圖片描述

2 多核CPU與記憶體共享的問題

  現在恐怕很難再找到單核心的CPU了,即使是我們的智慧手機,也至少是雙核的了,那麼問題就來了:在多核CPU的情況下,如何共享記憶體?
  如果擅長多執行緒高階程式設計,那麼你肯定會毫不猶豫地給出以下虛擬碼解決方案:

 synchronized(memory)
    {
             writeAddress(….)
    }

  如果真這麼簡單,那麼這個世界上就不會只剩下兩家獨大的主流CPU製造商了,而且可憐的AMD一直被Intel“吊打”。
  多核心CPU共享記憶體的問題也被稱為Cache一致性問題,簡單地說,就是多個CPU核心所看到的Cache資料應該是一致的,在某個資料被某個CPU寫入自己的Cache(L1 Cache)以後,其他CPU都應該能看到相同的Cache資料;如果自己的Cache中有舊資料,則拋棄舊資料。考慮到每個CPU有自己內部獨佔的Cache,所以這個問題與分散式Cache保持同步的問題是同一類問題。來自Intel的MESI協議是目前業界公認的Cache一致性問題的最佳方案,大多數SMP架構都採用了這一方案,雖然該協議是一個CPU內部的協議,但由於它對我們理解記憶體模型及解決分散式系統中的資料一致性問題有重要的參考價值,所以在這裡我們對它進行簡單介紹。
  首先,我們說說Cache Line,如果有印象的話,則你會發現I/O操作從來不以位元組為單位,而是以“塊”為單位,這裡有兩個原因:首先,因為I/O操作比較慢,所以讀一個位元組與一次讀連續N個位元組所花費的時間基本相同;其次,資料訪問往往具有空間連續性的特徵,即我們通常會訪問空間上連續的一些資料。舉個例子,訪問陣列時通常會迴圈遍歷,比如查詢某個值或者進行比較等,如果把陣列中連續的幾個位元組都讀到記憶體中,那麼CPU的處理速度會提升幾倍。對於CPU來說,由於Memory也是慢速的外部元件,所以針對Memory的讀寫也採用類似I/O塊的方式就不足為奇了。實際上,CPU Cache裡的最小儲存單元就是Cache Line,Intel CPU的一個Cache Line儲存64個位元組,每一級Cache都被劃分為很多組Cache Line,典型的情況是4條Cache Line為一組,當Cache從Memory中載入資料時,一次載入一條Cache Line的資料。下圖給出了Cache的結構。
          圖片描述
  每個Cache Line的頭部有兩個Bit來表示自身的狀態,總共有4種狀態。

  • M(Modified):修改狀態,其他CPU上沒有資料的副本,並且在本CPU上被修改過,與儲存器中的資料不一致,最終必然會引發系統匯流排的寫指令,將Cache
    Line中的資料寫回到Memory中。
  • E(Exclusive):獨佔狀態,表示當前Cache Line中包含的資料與Memory中的資料一致,此外,其他CPU上沒有資料的副本。
  • S(Shared):共享狀態,表示Cache
    Line中包含的資料與Memory中的資料一致,而且在當前CPU和至少在其他某個CPU中有副本。
  • I(Invalid):無效狀態,當前Cache Line中沒有有效資料或者該Cache
    Line資料已經失效,不能再用,當Cache要載入新資料時,優先選擇此狀態的Cache Line,此外,Cache Line的初始狀態也是I狀態。

MESI協議是用Cache Line的上述4種狀態命名的,對Cache的讀寫操作引發了Cache Line的狀態變化,因而可以理解為一種狀態機模型。但MESI的複雜和獨特之處在於狀態有兩種視角:一種是當前讀寫操作(Local Read/Write)所在CPU看到的自身的Cache Line狀態及其他CPU上對應的Cache Line狀態;另一種是一個CPU上的Cache Line狀態的變遷會導致其他CPU上對應的Cache Line的狀態變遷。如下所示為MESI協議的狀態圖。
         圖片描述
  結合這個狀態圖,我們深入分析MESI協議的一些實現細節。
  (1)某個CPU(CPU A)發起本地讀請求(Local Read),比如讀取某個記憶體地址的變數,如果此時所有CPU的Cache中都沒載入此記憶體地址,即此記憶體地址對應的Cache Line為無效狀態(Invalid),則CPU A中的Cache會發起一個到Memory的記憶體Load指令,在相應的Cache Line中完成記憶體載入後,此Cache Line的狀態會被標記為Exclusive。接下來,如果其他CPU(CPU B)在總線上也發起對同一個記憶體地址的讀請求,則這個讀請求會被CPU A嗅探到(SNOOP),然後CPU A在記憶體總線上複製一份Cache Line作為應答,並將自身的Cache Line狀態改為Shared,同時CPU B收到來自匯流排的應答並儲存到自己的Cache裡,也修改對應的Cache Line狀態為Shared。
  (2)某個CPU(CPU A)發起本地寫請求(Local Write),比如對某個記憶體地址的變數賦值,如果此時所有CPU的Cache中都沒載入此記憶體地址,即此記憶體地址對應的Cache Line為無效狀態(Invalid),則CPU A中的Cache Line儲存了最新的記憶體變數值後,其狀態被修改為Modified。隨後,如果CPU B發起對同一個變數的讀操作(Remote Read),則CPU A在總線上嗅探到這個讀請求以後,先將Cache Line裡修改過的資料回寫(Write Back)到Memory中,然後在記憶體總線上複製一份Cache Line作為應答,最後將自身的Cache Line狀態修改為Shared,由此產生的結果是CPU A與CPU B裡對應的Cache Line狀態都為Shared。
  (3)以上面第2條內容為基礎,CPU A發起本地寫請求並導致自身的Cache Line狀態變為Modified,如果此時CPU B發起同一個記憶體地址的寫請求(Remote Write),則我們看到狀態圖裡此時CPU A的Cache Line狀態為Invalid,其原因如下。
  CPU B此時發出的是一個特殊的請求——讀並且打算修改資料,當CPU A從總線上嗅探到這個請求後,會先阻止此請求並取得匯流排的控制權(Takes Control of Bus),隨後將Cache Line裡修改過的資料回寫道Memory中,再將此Cache Line的狀態修改為Invalid(這是因為其他CPU要改資料,所以沒必要改為Shared)。與此同時,CPU B發現之前的請求並沒有得到響應,於是重新發起一次請求,此時由於所有CPU的Cache裡都沒有記憶體副本了,所以CPU B的Cache就從Memory中載入最新的資料到Cache Line中,隨後修改資料,然後改變Cache Line的狀態為Modified。
  (4)如果記憶體中的某個變數被多個CPU載入到各自的Cache中,從而使得變數對應的Cache Line狀態為Shared,若此時某個CPU打算對此變數進行寫操作,則會導致所有擁有此變數快取的CPU的Cache Line狀態都變為Invalid,這是引發效能下降的一種典型Cache Miss問題。
  在理解了MESI協議以後,我們明白了一個重要的事實,即存在多個處理器時,對共享變數的修改操作會涉及多個CPU之間的協調問題及Cache失效問題,這就引發了著名的“Cache偽共享”問題。
  下面我們說說快取命中的問題。如果要訪問的資料不在CPU的運算單元裡,則需要從快取中載入,如果快取中恰好有此資料而且資料有效,就命中一次(Cache Hit),反之產生一次Cache Miss,此時需要從下一級快取或主存中再次嘗試載入。根據之前的分析,如果發生了Cache Miss,則資料的訪問效能瞬間下降很多!在我們需要大量載入運算的情況下,資料結構、訪問方式及程式演算法方面是否符合“快取友好”的設計,就成為“量變引起質變”的關鍵性因素了。這也是為什麼最近,國外很多大資料領域的專家都熱衷於研究設計和採用新一代的資料結構和演算法,而其核心之一就是“快取友好”。

3 著名的Cache偽共享問題

  Cache偽共享問題是程式設計中真實存在的一個問題,考慮如下所示的Java Class結構:

class MyObject 
{
 private long  a;
private long  b;
private long c;
}

 按照Java規範,MyObject的物件是在堆記憶體上分配空間儲存的,而且a、b、c三個屬性在記憶體空間上是近鄰,如下所示。
         圖片描述
  我們知道,X86的CPU中Cache Line的長度為64位元組,這也就意味著MyObject的3個屬性(長度之和為24位元組)是完全可能載入在一個Cache Line裡的。如此一來,如果我們有兩個不同的執行緒(分別執行在兩個CPU上)分別同時獨立修改a與b這兩個屬性,那麼這兩個CPU上的Cache Line可能出現如下所示的情況,即a與b這兩個變數被放入同一個Cache Line裡,並且被兩個不同的CPU共享。
              圖片描述
  根據MESI協議的相關知識,我們知道,如果Thread 0要對a變數進行修改,則因為CPU 1上有對應的Cache Line,這會導致CPU 1的Cache Line無效,從而使得Thread 1被迫重新從Memory裡獲取b的內容(b並沒有被其他CPU改變,這樣做是因為b與a在一個Cache Line裡)。同樣,如果Thread 1要對b變數進行修改,則同樣導致Thread 0的Cache Line失效,不得不重新從Memory里加載a。如此一來,本來是邏輯上無關的兩個執行緒,完全可以在兩個不同的CPU上同時執行,但陰差陽錯地共享了同一個Cache Line並相互搶佔資源,導致並行成為序列,大大降低了系統的併發性,這就是所謂的Cache偽共享。
  解決Cache偽共享問題的方法很簡單,將a與b兩個變數分到不同的Cache Line裡,通常可以用一些無用的欄位填充a與b之間的空隙。由於偽共享問題對效能的影響比較大,所以JDK 8首次提供了正式的普適性的方案,即採用@Contended註解來確保一個Object或者Class裡的某個屬性與其他屬性不在一個CacheLine裡,下面的VolatileLong的多個例項之間就不會產生Cache偽共享的問題:

@Contended
class VolatileLong {
  public volatile long value = 0L; 
}

4 深入理解不一致性記憶體

  MESI協議解決了多核CPU下的Cache一致性問題,因而成為SMP架構的唯一選擇。SMP架構近幾年迅速在PC領域(X86)發展,一個CPU晶片上整合的CPU核心數量越來越多,到2017年,AMD的ZEN系列處理器就已經達到16核心32執行緒了。SMP架構是一種平行的結果,所有CPU Core都連線到一個記憶體總線上,它們平等訪問記憶體,同時整個記憶體是統一結構、統一定址的(Uniform Memory Architecture,UMA)。如下所示給出了SMP架構的示意圖。
                  圖片描述
  但是,隨著CPU核心數量的不斷增長,SMP架構也暴露出其天生的短板,其根本瓶頸是共享記憶體匯流排的頻寬無法滿足CPU數量的增加,同時,一條“馬路”上通行的“車”多了,難免陷入“擁堵模式”。在這種情況下,分散式解決方案應運而生,系統的記憶體與CPU進行分割並捆綁在一起,形成多個獨立的子系統,這些子系統之間高速互連,這就是所謂的NUMA(None Uniform Memory Architecture)架構,如下圖所示。
  圖片描述
  我們可以認為NUMA架構第1次打破了“大鍋飯”的模式,記憶體不再是一個整體,而是被分割為相互獨立的幾塊,被不同的CPU私有化(Attach到不同的CPU上)。因此,當CPU訪問自身私有的記憶體地址時(Local Access),會很快得到響應,而如果需要訪問其他CPU控制的記憶體資料(Remote Access),則需要通過某種互連通道(Inter-connect通道)訪問,響應時間與之前相比變慢。 NUMA 的主要優點是伸縮性,NUMA的這種體系結構在設計上已經超越了SMP,可以擴充套件到幾百個CPU而不會導致效能嚴重下降。
  NUMA技術最早出現在20世紀80年代,主要執行在一些大中型UNIX系統中,Sequent公司是世界公認的NUMA技術領袖。早在1986年,Sequent公司就率先利用微處理器構建大型系統,開發了基於UNIX的SMP體系結構,開創了業界轉入SMP領域的先河。1999年9月,IBM公司收購了Sequent公司,將NUMA技術整合到IBM UNIX陣營中,並推出了能夠支援和擴充套件Intel平臺的NUMA-Q系統及解決方案,為全球大型企業客戶適應高速發展的電子商務市場提供了更加多樣化、高可擴充套件性及易於管理的選擇,成為NUMA技術的領先開發者與革新者。隨後很多老牌UNIX伺服器廠商也採用了NUMA技術,例如IBM、Sun、惠普、Unisys、SGI等公司。2000年全球網際網路泡沫破滅後,X86+Linux系統開始以低廉的成本侵佔UNIX的地盤,AMD率先在其AMD Opteron系列處理器中的X86 CPU上實現了NUMA架構,Intel也跟進並在Intel Nehalem中實現了NUMA架構(Intel伺服器晶片志強E5500以上的CPU和桌面的i3、i5、i7均基於此架構),至此NUMA這個貴族技術開始真正走入平常百姓家。
  下面我們詳細分析一下NUMA技術的特點。首先,NUMA架構中引入了一個重要的新名詞——Node,一個Node由一個或者多個Socket Socket組成,即物理上的一個或多個CPU晶片組成一個邏輯上的Node。如下所示為來自Dell PowerEdge系列伺服器的說明手冊中的NUMA的圖片,4個Intel Xeon E5-4600處理器形成4個獨立的NUMA Node,由於每個Intel Xeon E5-4600為8 Core,支援雙執行緒,所以每個Node裡的Logic CPU數量為16個,佔每個Node分配系統總記憶體的1/4,每個Node之間通過Intel QPI(QuickPath Interconnect)技術形成了點到點的全互連處理器系統。
          圖片描述
  其次,我們看到NUMA這種基於點到點的全互連處理器系統與傳統的基於共享匯流排的處理器系統的SMP還是有巨大差異的。在這種情況下無法通過嗅探匯流排的方式來實現Cache一致性,因此為了實現NUMA架構下的Cache一致性,Intel引入了MESI協議的一個擴充套件協議——MESIF。MESIF採用了一種基於目錄表的實現方案,該協議由Boxboro-EX處理器系統實現,但獨立研究MESIF協議並沒有太大的意義,因為目前Intel並沒有公開Boxboro-EX處理器系統的詳細設計文件。
  最後,我們說說NUMA架構的當前困境與我們對其未來的展望。
  NUMA架構由於打破了傳統的“全域性記憶體”概念,目前在程式語言方面還沒有任何一種語言從記憶體模型上支援它,所以當前很難開發適應NUMA的軟體。但這方面已經有很多嘗試和進展了。Java在支援NUMA的系統裡,可以開啟基於NUMA的記憶體分配方案,使得當前執行緒所需的記憶體從對應的Node上分配,從而大大加快物件的建立過程。在大資料領域,NUMA系統正發揮著越來越強大的作用,SAP的高階大資料系統HANA被SGI在其UV NUMA Systems上實現了良好的水平擴充套件。據說微軟將會把SQL Server引入到Linux上,如此一來,很多潛在客戶將有機會在SGI提供的大型NUMA機器上高速執行多個SQL Server例項。在雲端計算與虛擬化方面,OpenStack與VMware已經支援基於NUMA技術的虛機分配能力,使得不同的虛機執行在不同的Core上,同時虛機的記憶體不會跨越多個NUMA Node。
  NUMA技術也會推進基於多程序的高效能單機分散式系統的發展,即在4個Socket、每個Socket為16Core的強大機器裡,只要啟動4個程序,通過NUMA技術將每個程序繫結到一個Socket上,並保證每個程序只訪問不超過Node本地的記憶體,即可讓系統進行最高效能的併發,而程序間的通訊通過高效能程序間的通訊技術實現即可。

相關推薦

4未必知道記憶體知識

除了CPU,記憶體大概是最重要的計算資源了。基本成為分散式系統標配的快取中介軟體、高效能的資料處理系統及當前流行的大資料平臺,都離不開對計算機記憶體的深入理解與巧妙使用。本文將探索這個讓人感到熟悉又複雜的領域。 複雜的CPU與單純的記憶體多核CPU與記憶體共享的問題著名的

在node.js裡應該知道知識

1,exports===module.exports //true 注意:當exports被重新賦值之後,他兩就不會指向同一個物件了,資料就不會返回,但是返回資料的是module.exports!!! 2,解決npm載入慢------淘寶映象(因為訪問的是國外的伺服器) 使用cnpm:

大資料Hadoopx之HDFS模組中那些可能不知道知識

再給大家分享一些小知識,一起來瞧瞧吧! 一、namenode & secondarynamenode    1)namenode啟動(namenode格式化時會建立fsimage,edits兩個檔案,如果不是第一次啟動,會直接載入這兩個檔案到記憶體)。   2)secondary

必須知道的EF知識和經驗

部分 就是 serve 存在 效率 epo 命名空間 omap sql查詢 推薦MiniProfiler插件 數據準備 foreach循環的陷進 AutoMapper工具 聯表查詢統計 性能提升之AsNonUnicode 性能提升之AsNoTracking 多字段

學醫後才知道知識...

基本上 出現 影響 推薦 好處 大於 性激素 萎縮 原理 大學一位醫學老教授 說過這麽一段話:"人類有1/3的病不用治,1/3的病治不好,而我很慚愧,我只能看剩下那1/3疾病中的1/5。" 醫學就是激發人體自愈能力與發揮自然療法;人體三分之一的病是心理疾病,三分之

2019秋招必須知道的前端知識

引言 又是一輪金九銀十的校招黃金期,藉此更新部分前端面試題,並提供詳解(答案不保證百分百正確,但我自信,可參考性還是很高的),希望對大家會有幫助^~^! 版本 v0.1:新增HTML相關面試筆試題 HTML篇 (2018-9-15 19:10) 1. 你做過的網站

除了Hadoop,其他6必須知道的熱門大資料技術

      你知道新的市場領導者和曾經的領導者之間的關鍵區別是什麼嗎? 那就是“資料管理”。任何無法處理資料並將其投入使用的企業,很可能會讓位給那些能夠更好處理資料的。 事實上,大資料和其流動性的力量能促使企業發展。 大資料是大量資料的術語

4千萬不能錯過的Excel技巧!

Excel辦公軟體是每個職場人士都應該必備的一個技能之一,其實Excel也沒你想象的那麼難,只要多掌握幾個 技巧,就能幫你輕鬆解決一切煩惱,就看你學不學! 提取Excel身份證生日 不知道大家是怎麼將Excel身份證裡面的生日提取出來的?其實只需要現將第一個單元

除了Hadoop,還有6必須知道的熱門大資料技術

你知道新的市場領導者和曾經的領導者之間的關鍵區別是什麼嗎?   那就是“資料管理”。任何無法處理資料並將其投入使用的企業,很可能會讓位給那些能夠更好處理資料的。   事實上,大資料和其流動性的力量能促使企業發展。   大資料是大量資料的術語。由於

android log知道技巧

Android開發中,我們經常使用Log類來記錄log資訊,但是有時候我們輸出的log資訊太多,或者log中包含重要資訊,這時候我們僅僅希望只在開發環境中才輸出log,生產環境的安裝包不輸出日誌,一個小技巧就是檢測BuildConfig.DEBUG的值 if (BuildC

Windows圖示:有一些未必知道的東西

很奇怪,我的圖示明明不是這樣的,在資源管理器的資料夾裡面,我的圖示能夠正常顯示,在桌面的工作列裡,也能正常的顯示,唯獨在工作管理員裡顯示不正常。雖然不是什麼大問題,但是如果是一個產品釋出出去,會讓人覺得很不專業,會產生一定的負面影響。 這個圖示有點像是程式沒有圖示,使用的是系統預設的圖

Linux程式設計--程式設計前需要知道的基礎知識

1 PATH變數 當登陸進Linux系統時你與一個Shell程式進行互動,它在一組特定的路徑下進行指令的搜尋,一般稱為PATH環境變數,echo $PATH可以顯示搜尋路徑。當以普通使用者登陸時,系統的預設PATH路徑為 /bin:二進位制檔案目錄,一般存放

關於QT,需要知道這些基礎知識

Qt一開始是由奇趣公司開發的,後來被Nokia收購了,然後再被Digia收購了。所以有的人會誤以為Qt就是為了塞班系統而生,是個落伍的產物。但是很多嵌入式軟體、桌面工具都是用Qt來開發的,包括Quartus和Cadence也有用到Qt。誠然,Qt也是類似於C#、JAVA那樣,

9 應該知道的支付系統開源專案

如果你希望學習如何實現支付系統,那麼本文為大家列出的碼雲上 9 個優秀的支付開源專案,將有助於你瞭解在自己的應用中如何加入對支付功能的支援,希望能給大家帶來一點幫助。不足之處,歡迎討論交流:) 專案名稱: 龍果支付系統

5應該知道的CSS技術

這篇文章對一些人來說可能是多餘的。我很肯定這些技術已經被到處談論了,如果 你已經知道了,很好。對那些還不瞭解這些技術的人,打起精神來看看它們是如何做到 的吧。這些技術,熟練的 CSS 使用者都已經瞭然於心了,但是更多的新手或初學者還不知道。 無圖片圓角 這個技術變得越來越流行,因為許多人

11應該知道的django部落格引擎

這段時間一直在學python和django,準備寫個小小的blog鞏固下自己學到的東西,看到了GAE上的一些程式,大部分都是純python的,想找一些基於django的,還真是難。無意中搜索到一篇文章,就翻譯一下,渣技術,實在不行,就去看en文的吧。 en文地址 Mi

Xcode 9 倆必須知道的新功能

Xcode 9 beta 版已經可以下載了,不知道大傢伙對這個新版本開發工具看法如何,最近我費了一番周折終於體驗了一把,升級系統,下載Xcode,驗證安裝扒拉扒拉什麼的,幾乎搞了我一天,我做開發使用的並不是什麼 MacBook pro 筆記本, 而是Ma

5種未必知道的JavaScript和CSS互動的方法

隨著瀏覽器不斷的升級改進,CSS和JavaScript之間的界限越來越模糊。本來它們是負責著完全不同的功能,但最終,它們都屬於網頁前端技術,它們需要相互密切的合作。我們的網頁中都有.js檔案和.css檔案,但這並不意味著CSS和js是獨立不能互動的。下面要講的這五種Jav

Android之50知道的使用竅門

今天給大家分享下安卓系統的安卓手機的使用技巧方法,以時下最為普遍最主流的Android 2.3系統為例,不過大部分使用技巧在其他版本的安卓系統上同樣適用。   1.使用Android電源管理widget從Android2.1系統開始內建了一個非常強大的帶能源管理widget

5必須知道的Docker實用工具

Docker社群已經建立了許多開源的工具,更多的用例使得它比您想像的更有用。你可以在這裡查閱它們。你在網上能找到很多酷炫的Docker工具。絕大多數是開源的。 過去兩年,我已經積極地將Docker用到我的對大多數開發專案中。在你開始使用 Docker的時候,