1. 程式人生 > >YARN中記憶體和CPU兩種資源的排程和隔離實現詳解

YARN中記憶體和CPU兩種資源的排程和隔離實現詳解

Hadoop Yarn的資源隔離是指為執行著不同任務的“Container”提供可獨立使用的計算資源,以避免它們之間相互干擾。目前支援兩種型別的資源隔離:CPU和記憶體,對於這兩種型別的資源,Yarn使用了不同的資源隔離方案。對於CPU而言,它是一種“彈性”資源,使用量大小不會直接影響到應用程式的存亡,因此CPU的資源隔離方案採用了Linux Kernel提供的輕量級資源隔離技術Cgroup;對於記憶體而言,它是一種“限制性”資源,使用量大小直接決定著應用程式的存亡,Cgroup會嚴格限制應用程式的記憶體使用上限,一旦使用量超過預先定義的上限值,就會將該應用程式“殺死”,因此無法使用Cgroup進行記憶體資源隔離,而是選擇了執行緒監控的方式。需要解釋一下:為什麼應用程式的記憶體會超過預先定義的上限值?Java程式(Container)為什麼需要記憶體資源隔離?(1)為什麼應用程式的記憶體會超過預先定義的上限值?這裡的應用程式特指Yarn Container,它是Yarn NodeManager通過建立子程序的方式啟動的;Java建立子程序時採用了“fork() + exec()”的方案,子程序啟動瞬間,它的記憶體使用量與父程序是一致的,然後子程序的記憶體會恢復正常;也就是說,Container(子程序)的建立過程中可能會出現記憶體使用量超過預先定義的上限值的情況(取決於父程序,也就是NodeManager的記憶體使用量);此時,如果使用Cgroup進行記憶體資源隔離,這個Container就可能會被“kill”。(2)Java程式(Container)為什麼需要記憶體資源隔離?對於MapReduce而言,各個任務被執行在獨立的Java虛擬機器中,記憶體使用量可以通過“-Xms、-Xmx”進行設定,從而達到記憶體資源隔離的目的。然而,Yarn考慮到使用者應用程式可能會建立子程序的情況,如Hadoop Pipes(或者Hadoop Streaming),編寫的MapReduce應用程式中每個任務(Map Task、Reduce Task)至少由Java程序和C++程序兩個程序組成,這難以通過建立單獨的虛擬機器達到資源隔離的效果,因此,即使是通過Java語言實現的Container仍需要使用記憶體資源隔離。Yarn Container支援兩種實現:DefaultContainerExecutor和LinuxContainerExecutor;其中DefaultContainerExecutor不支援CPU的資源隔離,LinuxContainerExecutor使用Cgroup的方式支援CPU的資源隔離,兩者記憶體的資源隔離都是通過“執行緒監控”的方式實現的。基於執行緒監控的記憶體隔離方案1.配置引數(1)應用程式配置引數不同的應用程式對記憶體的需求不同,可以根據具體情況定義自己的引數,以MapReduce為例:mapreduce.map.memory.mb:MapReduce Map Task需要使用的記憶體量(單位:MB);mapreduce.reduce.memory.mb:MapReduce Reduce Task需要使用的記憶體量(單位:MB);(2)Hadoop Yarn NodeManager配置引數yarn.nodemanager.pmem-check-enabled:NodeManager是否啟用實體記憶體量監控,預設值:true;yarn.nodemanager.vmem-check-enabled:NodeManager是否啟用虛擬記憶體量監控,預設值:true;yarn.nodemanager.vmem-pmem-ratio:NodeManager Node虛擬記憶體與實體記憶體的使用比例,預設值2.1,表示每使用1MB實體記憶體,最多可以使用2.1MB虛擬記憶體;yarn.nodemanager.resource.memory-mb:NodeManager Node最多可以使用多少實體記憶體(單位:MB),預設值:8192,即8GB;2.實現原理Yarn NodeManager Container的記憶體監控是由ContainersMonitorImpl(org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorImpl)實現的,內部的MonitoringThread執行緒每隔一段時間就會掃描所有正在執行的Container程序,並按照以下步驟檢查它們的記憶體使用量是否超過其上限值。2.1構造程序樹如前所述,Container程序可能會建立子程序(可能會建立多個子程序,這些子程序可能也會建立子程序),因此Container程序的記憶體(實體記憶體、虛擬記憶體)使用量應該表示為:以Container程序為根的程序樹中所有程序的記憶體(實體記憶體、虛擬記憶體)使用總量。在Linux /proc目錄下,有大量以整數命名的目錄,這些整數是某個正在執行的程序的PID,而目錄/proc/<PID>下面的那些檔案分別表示著程序執行時的各方面資訊,這裡我們只關心/proc/<PID>/stat檔案即可。檔案/proc/<PID>/stat僅僅包含一行(多列)文字,可以通過正則表示式從中抽取程序的執行時資訊,包括:程序名稱、父程序PID、父程序使用者組ID、Session ID、使用者態執行的時間(單位:jiffies)、核心態執行的時間(單位:jiffies)、佔用虛擬記憶體大小(單位:page)和佔用實體記憶體大小(單位:page)等。ContainersMonitorImpl內部維護著每個Container程序的PID,通過遍歷/proc下各個程序的stat檔案內容(父程序PID、佔用虛擬記憶體大小和佔用實體記憶體大小),我們可以構建出每個Container的程序樹,從而得出每個程序樹的虛擬記憶體、實體記憶體使用總量。2.2判斷Container程序樹的記憶體使用量(實體記憶體、虛擬記憶體)是否超過上限值雖然我們已經可以獲得各個Container程序樹的記憶體(實體記憶體、虛擬記憶體)使用量,但是我們不能僅憑程序樹的記憶體使用量(實體記憶體、虛擬記憶體)是否超過上限值就決定是否“殺死”一個Container,因為“子程序”的記憶體使用量是有“波動”的,為了避免“誤殺”的情況出現,Hadoop賦予每個程序“年齡”屬性,並規定剛啟動程序的年齡是1,MonitoringThread執行緒每更新一次,各個程序的年齡加一,在此基礎上,選擇被“殺死”的Container的標準如下:
如果一個Contaier對應的程序樹中所有程序(年齡大於0)總記憶體(實體記憶體或虛擬記憶體)使用量超過上限值的兩倍;或者所有年齡大於1的程序總記憶體(實體記憶體或虛擬記憶體)使用量超過上限值,則認為該Container使用記憶體超量,可以被“殺死”。(注意:這裡的Container泛指Container程序樹)綜上所述,Yarn的記憶體資源隔離實際是記憶體使用量監控。3.原始碼分析3.1MonitoringThread執行緒監控的核心工作主要是由MonitoringThread(org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorImpl.MonitoringThread)完成的,內部就是一個“while”迴圈,以指定的時間間隔進行監控:
其中,時間間隔monitoringInterval由引數yarn.nodemanager.container-monitor.interval-ms指定,預設值:3000,單位:ms。下面介紹“while”迴圈的處理邏輯。3.2 將新啟動的Container加入監控列表以及將已完成的Container移出監控列表;每次監控開始之前都需要更新監控列表:trackingContainers,將新啟動的Container加入監控列表,由containersToBeAdded表示;將已完成的Container移出監控列表,由containersToBeRemoved表示。containersToBeAdded和containersToBeRemoved都是通過“事件”由org.apache.hadoop.yarn.server.nodemanager.containermanager.monitor.ContainersMonitorImpl.handle負責更新的,如下:
對於事件START_MONITORING_CONTAINER,它表示有新的Container程序,為其構建一個ProcessTreeInfo例項,用於儲存Container的程序樹資訊,也就是說,這裡考慮的不僅僅是Container程序,而是以Container程序為父程序的整個程序樹,建構函式引數含義依次如下:containerId:Container ID;pid:Container程序的PID;pTree:Container程序樹記憶體使用量計算器例項,不同的Hadoop執行平臺(Windows、Linux)因為統計記憶體使用量的方式不同,因此需要不同的計算器例項;通過該計算器例項,可以獲得當前Container程序樹的記憶體使用量;vmemLimit:Container程序樹可使用的虛擬記憶體上限值;pmemLimit:Container程序樹可使用的實體記憶體上限值;注意:pid、pTree的初始值為Null。更新監控列表trackingContainers之後,下一步就是對監控列表中的Container程序樹的記憶體使用量進行監控。3.3遍歷監控列表trackingContainers,逐個處理其中的程序樹;可以看出,監控列表trackingContainers中的每一個程序樹元素是由ContainerId和ProcessTreeInfo共同表示的。下面介紹單獨一個程序樹的記憶體監控過程。3.4初始化程序樹資訊ProcessTreeInfo;如3.2所述,程序樹監控列表trackingContainers是被不斷更新的,而新加入監控的Container程序樹資訊是由ProcessTreeInfo表示的,其中pid、pTree的初始值為Null,因此監控過程中如果發現程序樹資訊ProcessTreeInfo的pid、pTree為Null,要對其進行初始化。(1)獲取程序樹元素,由containerId和ptInfo表示;(2)判斷如果ptInfo(程序樹資訊)中的pId(Container程序的PID)為null,則表示需要初始化ptInfo;(3)獲取ProcessTreeInfo pid,將其儲存至pId;Container程序PID(pid)可以通過ContainerId(ptInfo.getContainerId())從ContainerExecutor(containerExecutor)中獲取;如果獲取不到相應的PID,可能是因為Container程序尚沒有被啟動或者ContainerExecutor已將其移除,也意味著此程序樹無需監控。(4)獲取ProcessTreeInfo pTree,將其儲存至pt;這裡需要介紹一下ResourceCalculatorProcessTree(org.apache.hadoop.yarn.util.ResourceCalculatorProcessTree)的作用。每一次對ProcessTreeInfo進行監控時,我們都必須獲取該程序樹內所有程序的執行狀態(這裡我們僅關心物理、虛擬記憶體使用情況等),也就是說,我們需要一個“計算器”,能夠將程序樹內所有程序的執行狀態計算出來,ResourceCalculatorProcessTree就是用來充當“計算器”角色的,如下注釋所示:ResourceCalculatorProcessTree是一個抽象類,也就意味著它可以有多種實現,具體選取哪一種實現取決於ResourceCalculatorProcessTree.getResourceCalculatorProcessTree:其中,processTreeClass由引數yarn.nodemanager.container-monitor.process-tree.class指定,預設值為null。因為傳入的引數clazz值為null,所以我們僅僅關注上圖紅色箭頭所指的邏輯即可。ProcfsBasedProcessTree和WindowsBasedProcessTree分別對應著ResourceCalculatorProcessTree在Linux平臺和Windows平臺的實現,通常我們關注ProcfsBasedProcessTree即可,也就是說,Linux平臺下pTree的例項型別為ProcfsBasedProcessTree。(5)將pId、pt更新至ptInfo,初始化過程完成;3.5根據ResourceCalculatorProcessTree(ProcfsBasedProcessTree)更新程序樹的執行狀態(這裡僅關注物理、虛擬記憶體),並獲取相關的監控資訊;(1)獲取當前程序樹的ResourceCalculatorProcessTree例項pTree,並更新其內部狀態updateProcessTree(),實際就是更新程序樹中的程序資訊(詳細處理邏輯見後);(2)獲取當前程序樹中所有程序的虛擬記憶體使用總量(currentVmemUsage)、實體記憶體使用總量(currentPmemUsage);(3)獲取當前程序樹中所有年齡大於1的程序的虛擬記憶體使用總量(curMemUsageOfAgedProcesses)、實體記憶體使用總是(curRssMemUsageOfAgedProcesses);(4)獲取當前程序樹的虛擬記憶體使用總量上限值(vmemLimit)、實體記憶體使用總量上限值(pmemLimit);3.6判斷程序樹的記憶體使用量是否超過上限值,虛擬記憶體與實體記憶體需要分別處理;isMemoryOverLimit的值用於表示程序樹的記憶體使用量是否超過上限值,值為true表示超量(虛擬記憶體或實體記憶體兩者至少有其一超量);值為false表示未超量(虛擬記憶體和實體記憶體兩者均未超量);初始值設定為false。(1)如果開啟虛擬記憶體監控,則判斷程序樹虛擬記憶體使用總量是否超過其上限值;(2)如果開啟實體記憶體監控,則判斷程序樹實體記憶體使用總量是否超過其上限值;虛擬、實體記憶體監控選項的開啟分別由引數yarn.nodemanager.vmem-check-enabled、yarn.nodemanager.pmem-check-enabled指定,預設值均為true,表示兩者均開啟監控。判斷虛擬、實體記憶體使用總量是否超過上限值由isProcessTreeOverLimit()(詳細處理邏輯見後)統一處理,兩者僅傳入的引數值不同,參考上圖程式碼。3.7如果isMemoryOverLimit值為true,則表示程序樹的記憶體使用量超量(或者虛擬記憶體、或者實體記憶體),執行“kill”並從監控列表移除;至此,程序樹記憶體使用總量監控處理邏輯完成。3.8ResourceCalculatorProcessTree(ProcfsBasedProcessTree) updateProcessTreeupdateProcessTree用於更新當前Container程序的程序樹:(1)獲取所有的程序列表;其中,procfsDir的值為/proc/,numberPattern表示的正則表示式為[1-9][0-9]*(用於匹配程序PID)。對於Linux系統而言,所以執行著的程序都對應著目錄“/proc/”下的一個子目錄,子目錄名稱即為程序PID,子目錄中包含著程序的執行時資訊。所謂的程序列表,實際就是Linux目錄“/proc/”下的這些程序子目錄名稱。程序列表processList包含的資訊:1、10、100、...。(2)更新程序樹processTree;因為Container程序樹中的程序隨時都可能啟動或停止,因此每次監控開始之前都需要更新該Container程序的程序樹;而且為了方便處理程序的年齡(加一),將該Container程序“舊”的程序樹processTree快取至oldProcs,然後清空processTree(詳情見後)。(3)遍歷(1)中程序列表,為每一個程序構建ProcessInfo,並將其儲存至allProcessInfo;ProcessInfo的構建過程由方法constructProcessInfo()完成,處理邏輯很簡單:a.讀取“procfsDir/<pid>/stat”(即“/proc/<pid>/stat”)的檔案內容,實際內容只有一行;b.通過正則表示式抽取其中的資訊,並更新至pInfo;可以看出,ProcessInfo儲存著一個程序的以下資訊:name:程序名稱;ppid:父程序PID;pgrpId:父程序所屬使用者組ID;session:程序所屬會話組ID;utime:程序使用者態佔用時間;stime:程序核心態佔用時間;vsize:程序虛擬記憶體使用量;rss:程序實體記憶體使用量;遍歷構建的過程中,如果發現“我”程序(即當前的Container程序),則將“我”儲存至程序樹processTree,因為當前的Container程序必須是此Container程序樹中的一員;如果沒有發現“我”程序,則表示Container程序(樹)已經執行結束,無需監控。(4)維護程序之間的父子關係;allProcessInfo中儲存著所有的程序資訊,其中key為PID,value為對應的ProcessInfo,我們通過ProcessInfo的ppid(父程序PID),即可以維護出這些程序之間的父子關係。對於每一個ProcessInfo(程序)pInfo:a.根據pInfo ppid找出其父程序的ProcessInfo:parentPInfo;b.將pInfo加入parentPInfo的子程序列表中(ProcessInfo addChild);(5)構建當前Container程序(即(3)中的me)的程序樹;a.將pInfoQueue初始化為me;b.如果pInfoQueue不為空,執行以下操作:b1.取出pInfoQueue的頭元素pInfo,將其加入程序樹processTree(注意重複檢測);b2.將pInfo的所有子程序加入pInfoQueue;c.執行b;上述流程執行完畢之後,processTree中儲存著當前Container程序的程序樹。(6)更新當前Container程序的程序樹中所有程序的年齡;處理邏輯很簡單:遍歷程序樹,對於其中的每一個ProcessInfo,如果它是一個“老”程序(即出現在“老”程序樹oldInfo中),則將其年齡加一。(注:ProcessInfo age初始值為一)到此,程序樹更新完畢。我們以虛擬記憶體為例說明程序樹的虛擬記憶體使用總量是如何計算的,如下:其實就是根據程序年齡做過濾,然後疊加ProcessInfo中的相關值(虛擬記憶體:vmem)。3.9ContainersMonitorImpl.isProcessTreeOverLimitisProcessTreeOverLimit用於判斷記憶體使用量是否超過上限值,虛擬記憶體和實體記憶體共用此方法。currentMemUsage:程序樹中所有程序的虛擬或實體記憶體使用總量;curMemUsageOfAgedProcesses:程序樹中所有年齡大於1的程序的虛擬或實體記憶體使用總量;vmemLimit:程序樹虛擬或實體記憶體使用上限;滿足以下二個條件之一,則認為程序樹記憶體使用超過上限:(1)currentMemUsage大於vmemLimit的兩倍,這樣做的目錄主要是為了防止誤判(見本文開篇所述);(2)curMemUsageOfAgedProcesses大於vmemLimit(年齡大於一的程序可以認記憶體使用比較“穩定”);

至此,Hadoop Yarn基於執行緒監控的記憶體隔離方案介紹完畢

yarn預設只管理記憶體資源,雖然也可以申請cpu資源,但是在沒有cpu資源隔離的情況下效果並不是太好.在叢集規模大,任務多時資源競爭的問題尤為嚴重.
還好yarn提供的LinuxContainerExecutor可以通過cgroup來隔離cpu資源

cgroup

cgroup是系統提供的資源隔離功能,可以隔離系統的多種型別的資源,yarn只用來隔離cpu資源

安裝cgroup

預設系統已經安裝了cgroup了,如果沒有安裝可以通過命令安裝
CentOS 6

yum install -y libcgroup

CentOS 7

yum install -y libcgroup-tools

然後通過命令啟動
CentOS 6

/etc/init.d/cgconfig start

CentOS 7

systemctl start cgconfig.service

檢視/cgroup目錄,可以看到裡面已經建立了一些目錄,這些目錄就是可以隔離的資源

drwxr-xr-x 2 root root 0 3月  19 20:56 blkio
drwxr-xr-x 3 root root 0 3月  19 20:56 cpu
drwxr-xr-x 2 root root 0 3月  19 20:56 cpuacct
drwxr-xr-x 2 root root 0 3月  19 20:56 cpuset
drwxr-xr-x 2 root root 0 3月  19 20:56 devices
drwxr-xr-x 2 root root 0 3月  19 20:56 freezer
drwxr-xr-x 2 root root 0 3月  19 20:56 memory
drwxr-xr-x 2 root root 0 3月  19 20:56 net_cls

如果目錄沒有建立可以執行

cd /
mkdir cgroup
mount -t tmpfs cgroup_root ./cgroup
mkdir cgroup/cpuset
mount -t cgroup -ocpuset cpuset ./cgroup/cpuset/
mkdir cgroup/cpu
mount -t cgroup -ocpu cpu ./cgroup/cpu/
mkdir cgroup/memory
mount -t cgroup -omemory memory ./cgroup/memory/

通過cgroup隔離cpu資源的步驟為

  1. 在cpu目錄建立分組
    cgroup以組為單位隔離資源,同一個組可以使用的資源相同
    一個組在cgroup裡面體現為一個資料夾,建立分組直接使用mkdir命令即可.
    組下面還可以建立下級組.最終可以形成一個樹形結構來完成複雜的資源隔離方案.
    每當建立了一個組,系統會自動在目錄立即建立一些檔案,資源控制主要就是通過配置這些檔案來完成
    --w--w--w- 1 root root 0 3月  19 21:09 cgroup.event_control
    -rw-r--r-- 1 root root 0 3月  19 21:09 cgroup.procs
    -rw-r--r-- 1 root root 0 3月  19 21:09 cpu.cfs_period_us
    -rw-r--r-- 1 root root 0 3月  19 21:09 cpu.cfs_quota_us
    -rw-r--r-- 1 root root 0 3月  19 21:09 cpu.rt_period_us
    -rw-r--r-- 1 root root 0 3月  19 21:09 cpu.rt_runtime_us
    -rw-r--r-- 1 root root 0 3月  19 21:09 cpu.shares
    -r--r--r-- 1 root root 0 3月  19 21:09 cpu.stat
    -rw-r--r-- 1 root root 0 3月  19 21:09 notify_on_release
    -rw-r--r-- 1 root root 0 3月  19 21:09 tasks
    yarn預設使用hadoop-yarn組作為最上層,任務執行時yarn會為每個container在hadoop-yarn裡面建立一個組
    yarn主要使用cpu.cfs_quota_us cpu.cfs_period_us cpu.shares3個檔案
    yarn使用cgroup的兩種方式來控制cpu資源分配
    1. 嚴格按核數隔離資源
      可使用核數 = cpu.cfs_quota_us/cpu.cfs_period_us
      在yarn中cpu.cfs_quota_us被直接設定為1000000(這個引數可以設定的最大值)
      然後根據任務申請的core來計算出cpu.cfs_period_us
    2. 按比例隔離資源
      按每個分組裡面cpu.shares的比率來分配cpu
      比如A B C三個分組,cpu.shares分別設定為1024 1024 2048,那麼他們可以使用的cpu比率為1:1:2
  2. 將程序id新增到指定組的tasks檔案
    建立完分組後只需要將要限制的程序的id寫入tasks檔案即可,如果需要解除限制,在tasks檔案刪除即可

yarn配置

啟動cgroup需要配置幾個配置檔案

etc/hadoop/yarn-site.xml配置

<property>
    <name>yarn.nodemanager.container-executor.class</name>
  <value>org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor</value>
</property>
<property>
    <name>yarn.nodemanager.linux-container-executor.resources-handler.class</name>
    <value>org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler</value>
</property>
<property>
    <description>yarn使用的cgroup組,預設為/hadoop-yarn</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.hierarchy</name>
    <value>/hadoop-yarn</value>
</property>
<property>
    <description>是否自動掛載cgroup</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.mount</name>
    <value>true</value>
</property>
<property>
    <description>cgroup掛載目錄, /sys/fs/cgroup 或者是 /cgroup,目錄和系統有關</description>
    <name>yarn.nodemanager.linux-container-executor.cgroups.mount-path</name>
    <value>/cgroup</value>
</property>
<property>
    <name>yarn.nodemanager.linux-container-executor.group</name>
    <value>hadoop</value>
</property>
<property>
    <description>配置nodemanager使用多少物理cpu資源,比如24核伺服器配置90的話,最近使用21.6核
            
           

相關推薦

YARN記憶體CPU資源排程隔離實現

Hadoop Yarn的資源隔離是指為執行著不同任務的“Container”提供可獨立使用的計算資源,以避免它們之間相互干擾。目前支援兩種型別的資源隔離:CPU和記憶體,對於這兩種型別的資源,Yarn使用了不同的資源隔離方案。對於CPU而言,它是一種“彈性”資源,使用量大小不

【微信小程式】在js匯入第三方js或自己寫的js,使用外部js的function的方法 importrequire的區別使用方法

如下 定義了一個外部js檔案,其中有一個function import lunaCommon from '../lunaCommon.js'; var ctx = wx.getStorageSync("ctx"); var filter = "/ms-code"; var apis

java工作筆記:web 程式設計關於jnijna工具操作效能對比測試

       第一次發部落格有點緊張哈。        最近剛剛公司轉崗從底層C語言的編寫到做Java的web restful架構。其中需要呼叫底層C++程式碼庫。所以對於選擇哪種方法從Java呼叫C的程式碼做了簡單地學習和對比測試。在這裡把他們貼出了。希望能有大神出來指點

AndroidBroadcast Receiver的註冊方法區別

broadcast receiver:用以監聽系統或使用者程式broadcast的Intent,它本質上是系統的一種全域性監聽器(與onXxxxListener相似但不同),只要存在與之匹配的Inte

Master原理剖析與原始碼分析:資源排程機制原始碼分析(schedule(),資源排程演算法)

1、主備切換機制原理剖析與原始碼分析 2、註冊機制原理剖析與原始碼分析 3、狀態改變處理機制原始碼分析 4、資源排程機制原始碼分析(schedule(),兩種資源排程演算法) * Dri

form表單getpost提交方式的區別

name bsp inpu get div post input 普通 表單 一、form表單中get和post兩種提交方式的區別?   1.get提交表單中的內容在鏈接處是可見的。post不可見   2.post相比於get是安全的   3.post不收限制大小,get有

Java的ReentrantLocksynchronized鎖定機制的對比

優化 實現 維護 pla 所有 投票 明顯 拋出異常 數據 多線程和並發性並不是什麽新內容,但是 Java 語言設計中的創新之一就是,它是第一個直接把跨平臺線程模型和正規的內存模型集成到語言中的主流語言。核心類庫包含一個 Thread 類,可以用它來構建、啟動和操縱線程,J

TF之RNN:TF的RNN的常用的定義scope的方式get_variableVariable—Jason niu

重復 及其 orf with gpo val 定義 系統 brush # tensorflow中的兩種定義scope(命名變量)的方式tf.get_variable和tf.Variable。Tensorflow當中有兩種途徑生成變量 variable import te

JDBCOracle的SIDServiceName方式的連接字符串格式

bottom none color bubuko div nbsp rac 字符串 padding SID格式: jdbc:oracle:thin:@<host>:<port>:<SID> 如: jdbc:oracle:thin:@19

C#Post請求的方式發送參數鏈Body的

連接 png ets return div 參數 try 發現 create POST請求 有兩種方式 一種是組裝key=value這種參數對的方式 一種是直接把一個字符串發送過去 作為body的方式 我們在postman中可以看到 sfdsafd sdfsdfds

js定時器setTimeoutsetInterval定時器

專案中,經常會用到定時器來實現資料實時更新、時間等,簡單總結一下: Javascript中的定時器有兩種,setInterval和setTimeout,而定時器的作用就是延遲執行。 一、定時器的寫法 setInterval(expression,milliseconds);

HTTP請求協議GETPOST基本請求方法的區別

GET在瀏覽器回退時是無害的,而POST會再次提交請求。   GET產生的URL地址可以被Bookmark,而POST不可以。   GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。   GET請求只能進行url編碼

HTTP協議GETPOST基本請求方法的區別

GET和POST兩種基本請求方法的區別 GET和POST是HTTP請求的兩種基本方法,要說它們的區別,接觸過WEB開發的人都能說出一二。   最直觀的區別就是GET把引數包含在URL中,POST通過request body傳遞引數。   你可能自己寫過無數個G

在Unity“Debug.Log”“Print”列印方式的區別

先寫個指令碼“PrintAndDebug”,掛在Main Camera 元件上,在指令碼的 Start 函式裡通過這兩種方式列印一段內容 然後執行u3d,看控制檯列印日誌,如下圖 在這裡可以明瞭的看到Debug.Log是直接打印出來的 而Print是繼承自MonoBehaviour的,

LivenessReadinessHealth Check手段在Kubernetes的使用

一.概述 強大的自愈能力是Kubernetes這一類容器編排管理引擎的一個重要特性。通常情況下,Kubernetes通過重啟發生故障的容器來實現自愈。除此之外,我們還有其他方式來實現基於Kubernetes編排的容器的健康檢查嗎?Liveness和Readiness就是不錯的選擇。 二.實踐步驟 2.1

scalar的基於OrderedOrdering比較器

1>Ordered class PP(var name: String, var age: Int) extends Ordered[PP] { override def compare(that: PP) = if (this.age > that.age) -1 else if (

numpya[][][] a[, , ]索引方式的區別

之前一直對a[][][] 和 a[, , ]兩種索引方式的區別不清楚,今天試驗了一下。 根據三個維度分別是:還是數字,共2^3^ =8種情況進行了實驗。 1、a[:][:][:] 與 a[:, :, :](等價於a[:]), a[1][0][2] 與 a[1,

HTML5sessionStoragelocalStorage儲存方式的使用

<head> <meta charset="utf-8"> <title>HTML5 本地儲存</title> <script type="text/javascript"> function $(id){retur

JS刪除JSON陣列的元素的方法:deletesplice

最近的需求中,需要從JSON陣列中刪除元素,之前不太瞭解,特地查了一下,總結一下: splice(startIndex,count);這個方法用於從陣列的第startIndex位開始,刪除count個元素。 說明: 1、滿足條件的元素直接被刪除,腳標重信排 2、sta

獲取IOC容器的bean的方式(idclass)的區別

// ClassPathXmlApplicationContext: 是 ApplicationContext的實現類,從類路徑下來載入配置檔案 ApplicationContext ctx=new ClassPathXmlApplicationContext("a