教材:10710周志遠教授平行程式 https://www.youtube.com/playlist?list=PLS0SUwlYe8cxqw70UHOE5n4Lm-mXFXbZT 20250915 筆記 內容可能有錯僅供參考 在這個章節開始投影片和10710周志遠教授平行程式有差異,接下來以 NTHU-PP-2021 (Chinese) 為主 [NTHU-PP-Chap10-Big Data-Part2](https://www.youtube.com/watch?v=FNgJv4A63Dc&list=PLQTDfc8kgjhMKtgumyK0gmEelnTtqJGsp&index=23) 搭配 22A~22B Distributed Computing for Big Data Using MapReduce 開始進入到分散式計算和系統 今日大綱 1.Hadoop 概述 2.Hadoop 生態系統 3.巨量資料處理的演變 4.HDFS 介紹 5.MapReduce 介紹 ### **巨量資料與資料工程 (Big Data and Data Engineering)** * **核心變革**:巨量資料時代最大的改變是出現了新的資料處理軟體工具,這些工具讓使用者或資料分析師能夠探索更多樣式、更大量的資料,從中發掘有用的價值。 * **關鍵工具**:最具代表性的工具是 Google 的 MapReduce 及它的開源版本 Hadoop。 * Hadoop 是一個開源專案,因此發展成為一個龐大的生態系統 (ecosystem),因為軟體最重要的是建立環境,有了這樣的環境,才會吸引更多人使用並解決問題。 * **資料工程的重要性**:資料工程 (Data Engineering) 的任務是將軟體安裝起來供他人使用。在巨量資料領域,這項工作非常專業且需要經驗,因為它涉及熟悉數十種軟體,並了解它們之間如何整合、相依與協作。這需要設計資料處理架構,並解決不同軟體版本之間的相容性問題和效能優化。 --- ### **Hadoop 概述** * **定義**:Hadoop 是一個非常著名的開源專案,本身是一個分散式框架 (distributed framework)。它允許使用者在此框架上開發各種資料處理程式與應用。 * **特性**: * **分散式計算**:Hadoop 是一個分散式計算軟體。 * **可靠性 (Reliability) 與可擴展性 (Scalability)**:Hadoop 特別強調可靠性和可擴展性。它設計用於在可能不穩定或便宜的計算環境(例如可能故障的電腦)中運行。即使有電腦故障,框架也能確保計算持續進行,而無需重新運行整個程式。 * **容錯 (Fault Tolerance)**:當電腦數量眾多(例如一萬台)時,任何一台電腦故障的機率都非常高。Hadoop 平台能夠做到可擴展且容忍這些故障。 * **成本與時間效益**:Hadoop 系統設計的初衷是希望能以合理的成本和時間來處理巨量資料,以便大家能夠真正探索這些大量的資料。 * **核心組件**:Hadoop 本身包含了幾個核心組件,最初是三個獨立的專案,後來演變成 Hadoop 的核心。這些專案受到 Google 相關專案的啟發或實作。 * **HDFS (Hadoop Distributed File System)**:負責資料儲存,是一個分散式檔案系統,靈感來自 Google File System (GFS)。 * **MapReduce**:負責計算,是基於 Google MapReduce 論文實作的計算框架。 * **YARN (Yet Another Resource Negotiator)**:是一個資源管理器 (resource manager) 或協調者 (negotiator)。 * **功能**:負責分配不同電腦上的計算或儲存資源。其目的與當前熱門的容器 (container) 技術相似,用於資源分配和環境隔離 (isolation)。 * **資源共享**:與超級電腦不同,分散式計算常將多個工作 (job) 混雜在同一台電腦上執行,甚至有些工作只需部分 CPU/GPU 資源。YARN 處理資源共享問題,根據使用者需求分配資源,並確保計算工作之間不會互相干擾(主要是計算環境的干擾,而非效能)。 * **環境隔離**:透過容器技術(例如 Docker 等)實現環境隔離,讓不同環境依賴性的工作可以在同一台實體電腦上共用計算資源,而軟體環境互不衝突。 * **動態資源配置**:在沒有 YARN 的情況下,MapReduce 的計算工作類型(Map task 和 Reduce task)對應的硬體資源槽 (mapper slot, reducer slot) 是固定的。有了 YARN 之後,可以動態地創建不同數量的 Map slot 和 Reduce slot,使計算資源得到更充分的利用。 * **Common Utilities**:是大家都會用到的一些工具庫 (utility library) 和函式。 * **整合效益**:MapReduce、HDFS 和 YARN 雖然是獨立的專案,但它們可以一起安裝,發揮最大的效益。 * MapReduce 和 HDFS 整合時,Map 或 Reduce 計算工作有較高機會從本地磁碟 (local disk) 撈取資料,減少透過網路遠端存取的延遲,因為巨量資料透過網路傳輸可能會成為瓶頸。 --- ### **Hadoop 生態系統 (Hadoop Ecosystem)** * **定義**:Hadoop 生態系統泛指 Hadoop 核心組件之外,所有與 Hadoop 組件結合的巨量資料解決方案,特別是資料分析解決方案。這是一個非常龐大的系統,可能包含上百個專案。 * **常見組件範例**: * **Zookeeper**:負責協調和監控整個系統的運作情況,確保分散式系統中共享資料的一致性 (data consistency),透過投票機制來達成。 * **HBase**:是一個 NoSQL 資料庫,非常接近 Google 的 BigTable 專案。 * **Hive**:提供 SQL 語言介面,讓使用者可以直接寫 SQL 查詢來分析 HDFS 上的資料,而不需寫 MapReduce 程式。Hive 會將 SQL 查詢轉換成 MapReduce 程式。 * **Pig**:也提供類似 SQL 的語言介面,將查詢轉換成 MapReduce 程式。 * **Mahout (MLlib)**:是一個分散式的機器學習函式庫 (machine learning library),用於在分散式系統上處理巨量資料並實作機器學習演算法。 * **Sqoop**:負責在不同類型的資料庫(如關聯式資料庫 SQL 和 NoSQL)之間進行資料格式轉換的工具。 * **Flume**:一個分散式串流系統 (distributed streaming system),讓資料以串流方式進入 HDFS 或其他資料儲存系統。 * **資料工程師的角色**:資料工程師必須熟悉這些各式各樣的軟體,並了解它們彼此間的相依性 (dependency) 和整合方式。他們需要設計資料處理基礎設施 (data processing infrastructure),並將這些獨立開發的專案連結起來。由於軟體版本升級可能導致相容性問題,資料工程師還需處理優化,包括調整系統架構、資料壓縮、傳輸和過濾的順序等複雜問題。 * **商業模式**:儘管所有巨量資料軟體幾乎都是開源的 (open source),但業界在實際使用和整合時面臨挑戰。因此,存在像 Cloudera 這樣的公司,它們負責為客戶建立所需的資料平台,管理開源社群、主導開源發展,並提供專業的部署和維護服務。Cloudera 可能提供兩種解決方案:一套完全基於開源組件,另一套包含自行優化的非開源組件,後者可能效能更佳,但整合性較差。 --- ### **巨量資料處理的演變 (Evolution of Big Data Processing)** * **處理重點轉移**:目前的巨量資料處理,除了傳統的資料量 (Size) 問題外,更注重資料的**速度 (Velocity)** 和 **多樣性 (Variety)**。 * **新興技術**: * **Spark**:由於現代電腦記憶體 (memory) 越來越大,Spark 等軟體開始利用記憶體而非檔案系統作為主要資料存取的地方。Spark 也增加了類似 SQL 的介面。 * **SQL 介面普及**:對於許多非程式背景的資料分析師而言,他們更喜歡使用 SQL 語言進行資料分析,而不需撰寫程式碼。因此,像 Hive 和 SparkSQL 這樣的專案變得越來越重要。 * **串流處理 (Streaming Processing)**:物聯網 (IoT)、手機和 5G 應用產生大量即時資料,需要即時處理和收集。串流處理因此受到越來越多重視。 * **著名串流處理工具**:Kafka 是一個非常著名的分散式串流處理軟體,其他還有 Storm 等。 * **批次處理 (Batch Processing)**:與串流處理相對,批次處理是處理大批量資料,一次性長時間運行的傳統處理方式。 * **Hadoop 核心組件的現狀**: * **MapReduce**:雖然是課程重點,且最初廣泛使用,但現在實際使用者已非常少。其主要原因在於它主要處理傳統的資料量問題,而現代處理更關注速度和多樣性。 * **HDFS**:仍然持續存在且非常重要,因為資料始終需要儲存。許多 Hadoop 生態系統的應用仍然強調資料儲存在 HDFS 上。 * **YARN**:隨著容器技術的興起,使用 YARN 的人越來越多。然而,近期像 Docker 和 Kubernetes 等更強大的雲端協調器出現,YARN 的使用量可能略有下降,但作為基礎概念,它仍然非常重要。 * **基礎概念的重要性**:儘管某些工具的使用量可能隨時間演變,但像 Hadoop 這樣的基礎概念仍然是理解巨量資料處理不可或缺的一部分,如同 Linux 對作業系統的重要性。 --- ### **HDFS (Hadoop Distributed File System) 介紹** * **目的**:解決巨量資料最基本的儲存問題,能夠儲存單一檔案即使它達到 PB 級別的大小。 * **儲存原理**:利用平行 I/O (P-IO) 特性,將一個大檔案切分成許多小檔案塊 (block),並分散儲存到不同的電腦磁碟上。這不僅增加了儲存容量,也提升了 I/O 效能。 * **關鍵特性**: 1. **資料複製 (Data Replication)**:HDFS 會將每個資料塊複製成三份 (預設),並儲存在系統中。 * **原因**:基於「個體電腦節點不可靠,隨時可能崩潰」的假設,確保資料的可靠性,避免資料丟失。 * **好處**:增加了平行 I/O 的程度,同一個檔案可以從三個不同位置讀取。 2. **針對批次處理的優化 (Optimization for Sequential Read)**:HDFS 的設計專門針對巨量資料處理,特別優化了連續讀取 (sequential read)。 * **限制**:不支援隨機寫入 (random write) 或覆寫 (overwrite),只支援附加 (append-only)。新資料只能在現有資料的末尾追加。 * **原因**:避免資料一致性 (data consistency) 問題。如果支援隨機寫入,當多個 process 同時讀寫共享資料時,會出現競爭條件 (race condition) 和平行問題。限制寫入方式可以減少同步機制的複雜性,對於可擴展的分散式系統非常重要。 3. **大檔案塊大小 (Large Block Size)**:HDFS 的存取單位將資料切分成較大的塊大小,通常為 64MB。 * **原因**:巨量資料通常是 TB 級別,切分過小的塊會增加元資料 (metadata) 的管理負擔。 * **影響**:檔案必須夠大才能被切分成足夠多的塊並分散儲存。小於塊大小的檔案將無法充分利用分散式儲存的優勢。 * **應用匹配**:這些設計選擇是為了符合巨量資料分析的應用需求,因為大多數分析只需要讀取資料進行分析 (sequential read),而很少修改原始資料 (raw data)。即使要寫入資料,通常也是以追加方式寫入。 * **HDFS 架構**: * **簡潔性**:HDFS 採用客戶端-伺服器 (client-server) 架構,設計越簡單越好以提高可擴展性。 * **組件**: * **NameNode**:負責控制資料存取 (control data access),管理元資料 (metadata),例如檔案位置、存取權限等。它是整個系統的控制平面 (control plane)。 * **DataNode**:負責儲存資料,檔案塊被分散儲存到這些節點上。它是資料平面 (data plane),純粹負責資料的 I/O 儲存。DataNode 使用其本地檔案系統來儲存資料塊,HDFS 只是其上的資料管理層。 * **Client**:應用程式透過 HDFS 的 API (例如 GFSC) 與 NameNode 通訊,獲取資料位置和權限資訊後,直接與 DataNode 進行資料傳輸,不經過 NameNode。 * **心跳訊息 (Heartbeat Message)**:NameNode 與 DataNode 之間透過心跳訊息確保 NameNode 知道哪些 DataNode 節點是存活的。如果 DataNode 節點故障,NameNode 可以執行資料塊的重新複製 (replication) 和恢復 (recovery) 操作。 * **Chunk 儲存**:檔案被切分成 64MB 的塊 (chunk),每個 chunk 複製三份,分散儲存在不同的 DataNode 上。DataNode 上儲存的檔案是亂碼名稱,它不知道這些檔案屬於哪個使用者或哪個文件,這些映射關係由 NameNode 管理。 --- ### **MapReduce 介紹** * **起源**:源自 Google 的 MapReduce 論文,Hadoop 的 MapReduce 是其 Java 版本的開源實作。 * **三種含義**: 1. **程式設計模型 (Programming Model)**:最簡單的「分而治之 (divide and conquer)」實作。它只包含兩個階段:Map 和 Reduce。 2. **實作 (Implementation)**:指 Google 實際的 MapReduce 軟體。 3. **系統架構 (System Architecture)**:指 Hadoop 實現的 MapReduce 系統架構,包括排程 (scheduling) 等機制。 * **程式設計模型詳述**: * **分而治之**:選擇這種方式是因為它具有最高的平行度,最容易實現可擴展性 (scalable)。 * **Map 階段**:將計算工作分配到不同的工作節點 (worker),將資料分割成許多獨立的計算任務 (independent computing tasks)。每個 Map task 獨立處理一個記錄 (record),不知道其他記錄的存在,避免依賴性。 * **Reduce 階段**:將 Map 階段的計算結果進行聚合 (aggregation) 或歸約 (reduce),得到最終結果。 * **限制性**:MapReduce 模型相對簡單且有限制,這也是後來出現更複雜、更通用程式設計模型的系統的原因。 * **基本巨量資料分析的五個步驟**: * MapReduce 非常適合基本的巨量資料處理,因為大多數巨量資料分析的低階計算不外乎這五個步驟: 1. 將大資料切分成許多記錄 (record)。 2. 從每個記錄中提取有用資訊 (Map function)。 3. 對這些有用資訊進行整合,例如分組 (grouping)。 4. 根據每個類別對處理過的資訊(中間結果)進行聚合或統計分析 (Reduce function)。 5. 將最終結果寫出。 * **程式設計焦點**:程式設計師只需定義和實作 Map function 和 Reduce function (步驟 2 和 4)。其他步驟(資料分區、洗牌和排序、輸出)都由框架自動處理。 * **資料結構**:Map function 的輸入和 Reduce function 的輸出都是鍵值對 (key-value pair)。鍵和值的類型沒有限制,可以自定義。 * **Word Count 範例**: * **輸入**:多行文字資料,每行被視為一個記錄。 * **Map 階段**:每個 Map task 處理一行文字。它會掃描文字,將每個單字 (word) 作為鍵 (key),值 (value) 為 1(表示出現一次),輸出中間鍵值對 (intermediate key-value pairs)。 * **Shuffle 與 Sort 階段**: * **Shuffle**:將相同鍵的值(相同單字的所有「1」)分組 (grouping)。 * **Sort**:對鍵進行排序(例如按字母順序),這對許多應用來說很有用,因為排序後的資料便於搜尋。此步驟由 MapReduce 框架自動執行。 * **Reduce 階段**:每個 Reduce task 接收一個鍵和該鍵所有值的列表。對於 Word Count,它會遍歷列表,將所有「1」相加,得到該單字的總出現次數。 * **輸出**:Reduce task 將最終的單字計數結果寫入輸出檔案。 * **平行計算的抽象**:程式設計師在撰寫 Map function 和 Reduce function 時,不需要考慮平行計算的細節。Map function 只針對單一記錄進行處理,Reduce function 只針對單一鍵及其所有值進行聚合。框架負責處理平行化,讓非平行程式背景的人也能寫出可平行處理資料的程式。 * **框架的職責 (Framework's Responsibilities)**: * **排程 (Scheduling)**:Master (JobTracker) 負責將 Map task 和 Reduce task 分配到工作節點 (TaskTracker) 上。 * **資料分佈 (Data Distribution)**:確保任務能找到其所需的資料。MapReduce 的排程器感知資料位置 (data-aware),會將處理特定資料的進程丟到該資料所在的節點上,以減少資料移動的成本和時間。 * **標準化與同步化 (Standardization and Synchronization)**:處理分組 (grouping)、排序 (sorting)、洗牌 (shuffle) 等過程中的同步化需求。 * **錯誤處理 (Fault Handling)**:偵測工作節點故障,並重新安排計算任務,確保計算繼續進行。 * **「將處理移至資料 (Move Process to Data)」概念**: * **傳統模式**:在傳統的超級電腦或資料處理架構中,計算節點 (compute nodes) 和儲存節點 (storage nodes) 通常是分開的。處理資料時,必須透過網路將資料從儲存系統傳輸到計算系統,這在處理巨量資料時會造成瓶頸。 * **MapReduce 方法**:將儲存節點和計算節點結合在一起。每個節點既負責資料儲存,也負責資料計算。這樣,在處理資料時,計算就有機會直接從本地磁碟存取資料,避免了昂貴的網路傳輸。這是 MapReduce 與 HDFS 整合在同一組節點上的主要原因。 * **Hadoop 集群角色 (Hadoop Cluster Roles)**: * 在同一組節點上,HDFS 和 MapReduce 作為獨立系統運行,各自有其 Master 和 Slave。 * **NameNode**:HDFS 的 Master,負責管理檔案系統的元資料。 * **DataNode**:HDFS 的 Slave,負責實際儲存資料塊。 * **JobTracker**:MapReduce 的 Master,負責計算任務的排程。 * **TaskTracker**:MapReduce 的 Slave,提供 Map slot 和 Reduce slot,負責執行 Map function 和 Reduce function 任務。 * **協作方式**:當 Map 或 Reduce task 在節點上執行時,它會向 NameNode 詢問所需資料塊的位置。如果 JobTracker 預先進行了資料感知排程 (data-aware scheduling),那麼資料塊很可能就在 TaskTracker 所在的本地節點上,TaskTracker 就可以直接呼叫本地檔案系統來存取資料,避免網路傳輸。 * **MapReduce 執行流程**: 1. **輸入檔案分割**:輸入檔案被 HDFS 分割成多個塊 (chunk)。 2. **Map Task 生成與排程**:JobTracker 會為每個檔案塊生成一個 Map task。Map task 被排程到擁有該資料塊的機器上。 3. **本地讀取**:Map task 執行資料讀取時,是從本地檔案系統進行讀取 (local read),不涉及網路傳輸。 4. **Map 執行與中間鍵值對輸出**:Map task 執行 Map function,產生中間鍵值對。 5. **Shuffle 與 Sort**:這些中間鍵值對根據鍵進行排序和分組。框架會將它們分發到不同數量的「桶 (bucket)」中,每個桶對應一個 Reduce task。 * Map task 會將中間結果寫入其本地磁碟 (local disk) 作為緩衝 (buffer),而非 HDFS。 * **遠端讀取 (Remote Read)**:這是 MapReduce 過程中唯一必須使用網路的地方。Reduce task 需要從所有 Map task 的本地磁碟上拉取其所需的所有鍵值對。 * **優化**:通常,Map reduce 的目的是資訊提取 (information extraction),所以中間結果的資料量會遠小於輸入資料量。這樣設計是為了讓大量資料只需進行本地存取,而少量提取出的資料才需要進行遠端傳輸。 6. **Reduce 執行**:Reduce task 接收特定鍵的所有值,執行 Reduce function 進行聚合。每個 Reduce task 會處理它負責的所有鍵,並根據排序順序依序處理。 7. **輸出**:每個 Reduce task 將其處理結果寫入一個單獨的輸出檔案。這些檔案的內容會按照鍵的順序輸出。多個輸出檔案可以被合併。 * **記憶體效率**:MapReduce 處理大資料量問題,其效率高的一個原因在於它整個計算過程幾乎不需要大量記憶體。它一次只處理一個鍵值對或一個記錄,記憶體主要作為串流緩衝使用。它能夠處理記錄數量極大甚至無限大的資料問題。 --- 其他課程連結 [平行程式1C~2B Introduction parallel programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/Syxh3H7Kxe) [平行程式3A~3D The Latest Developments and Applications Using Parallel Programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJh7QFVKle) [平行程式4A~4B IO Parallel IO and Program Analysis](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJLMsuHFgg) [平行程式5A~5B The Latest Developments and Applications Using Parallel Programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/SJh57hIFle) [平行程式6A~6B Communication Routines and Parallel Function Code](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/r1X9kX_Fle) [平行程式 6C~6D Communication Routines and Parallel Function Code](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/S1DPjoYFlx) [平行程式 7A~8A Pthread:Synchronization Problem & Tools](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJu-_0tKge) [平行程式 8B~8D Synchronization Tools & Open Multi-Processing(OpenMP)](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1ki4E2Fee) [平行程式 9A~9B Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJTYMrpKlx) [平行程式 10A~10B Synchronization Tools & Open Multi-Processing Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/B1cY6M1qee) [平行程式 10C~10D Synchronization Tools & Open Multi-Processing Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BkgFaNg5gg) [平行程式 11A~11B Parallel Work Pool and Termination / Parallel Sorting](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1hfOw-5xl) [平行程式 12A~12B Parallel Sorting and Pipelined Computations](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/Symo-zQ9eg) [平行程式 12C~12D Parallel Sorting and Pipelined Computations](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJYNKDVceg) [平行程式 13A-13B Sychronous Parallelism](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJ2UJ2Bqex) [平行程式 14A~14B Heterogeneous Computing](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BksS4yP5eg) [平行程式 14C~14D Heterogeneous Computing](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJrfTUd9xx) [平行程式 15A~15B Parallel Programming Model on GPU](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/ByWnl-t5gg) [平行程式 16A~16B What is Compute Unified Device Architecture(CUDA)?](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HyYpsjcqgl) [平行程式 17A~18A 平行運算的CUDA](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1dUeBT5lg) [平行程式 18B~19A 記憶體層級 / CUDA的優化](https://hackmd.io/@JuitingChen/HyF44e1jge) [平行程式 19B~19D 記憶體層級 / CUDA的優化 ](https://hackmd.io/@JuitingChen/ryPEu4lieg) [平行程式 20A~20B CUDA優化全域和區域記憶體/共享記憶體](https://hackmd.io/@JuitingChen/r1X659Zoxl) [平行程式 21A~21B Parallel Reduction / Distributed Computing Framework](https://hackmd.io/@JuitingChen/HyiOpozjxl) [平行程式 NTHU-PP-Chap10-Big Data-Part1 ](https://hackmd.io/@JuitingChen/Hyc-e3Golx) [平行程式 NTHU-PP-Chap10-Big Data-Part2 ](https://hackmd.io/@JuitingChen/ryC_QTXoxl) [平行程式 NTHU-PP-Chap11-MapReduce](https://hackmd.io/@JuitingChen/HJgBXJOsge) [平行程式 NTHU-PP-Chap12-Distributed Training-Part1](https://hackmd.io/@JuitingChen/ryh5hBtsge) [平行程式 NTHU-PP-Chap12-Distributed Training-Part2](https://hackmd.io/@JuitingChen/rJ2G7kdjxg) [平行程式 NTHU-PP-Chap12-Distributed Training-Part3](https://hackmd.io/@JuitingChen/HkA471dilx) [平行程式 NTHU-PP-Chap13-UCX-Part1](https://hackmd.io/@JuitingChen/rJbq103ieg) [平行程式 NTHU-PP-Chap13-UCX-Part2](https://hackmd.io/@JuitingChen/SJpNmk_ixl) [平行程式 NTHU-PP-Chap13-UCX-Part3](https://hackmd.io/@JuitingChen/HkIUYa13xe)
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up