- vừa được xem lúc

Multi-thread, Multi-process, CPU bound multi-thread hay multi-process?

0 0 6

Người đăng: Tú Phi Anh

Theo Viblo Asia

Bài viết nằm trong series Multi-thread programming in depth

1. Multi-thread

Từ định nghĩa về Thread ở bài viết trước Thread và Process, mình thấy rằng Multi-thread là một tổ hợp nhiều thread riêng lẻ với nhau.

Multi-thread (đa luồng) là một tiến trình thực hiện nhiều luồng đồng thời. Một ứng dụng Java ngoài luồng chính có thể có các luồng khác thực thi đồng thời làm ứng dụng chạy nhanh và hiệu quả hơn. VD: Trình duyệt web hay các chương trình chơi nhạc là 1 ví dụ điển hình về đa luồng.

  • Khi duyệt 1 trang web, có rất nhiều hình ảnh, CSS, javascript… được tải đồng thời bởi các luồng khác nhau.
  • Khi play nhạc, chúng ta vẫn có thể tương tác được với nút điều khiển như: Play, pause, next, back … vì luồng phát nhạc là luồng riêng biệt với luồng tiếp nhận tương tác của người dùng.

1.1 Ưu điểm

  • Nó không chặn người sử dụng vì các luồng là độc lập và bạn có thể thực hiện nhiều công việc cùng một lúc.
  • Mỗi luồng có thể dùng chung và chia sẻ nguồn tài nguyên trong quá trình chạy, nhưng có thể thực hiện một cách độc lập.
  • Luồng là độc lập vì vậy nó không ảnh hưởng đến luồng khác nếu ngoại lệ xảy ra trong một luồng duy nhất.
  • Có thể thực hiện nhiều hoạt động với nhau để tiết kiệm thời gian. Ví dụ một ứng dụng có thể được tách thành : luồng chính chạy giao diện người dùng và các luồng phụ nhiệm gửi kết quả xử lý đến luồng chính.

1.2 Nhược điểm

  • Càng nhiều luồng thì xử lý càng phức tạp.
  • Xử lý vấn đề về tranh chấp bộ nhớ, đồng bộ dữ liệu khá phức tạp.
  • Cần phát hiện tránh các luồng chết (dead lock), luồng chạy mà không làm gì trong ứng dụng cả. (Mình sẽ nói chi tiết về deadlock trong một bài viết khác)

2. Multi-process

Multiprocessing hay Multi-process là khả năng của một hệ thống hỗ trợ nhiều bộ vi xử lý processor cùng một lúc. Các ứng dụng trong hệ thống đa xử lý được chia thành nhiều quy trình nhỏ và chạy độc lập, và hệ điều hành sẽ phân bổ các luồng này cho bộ vi xử lý để cải thiện hiệu suất của hệ thống. Thực tế thì không phải ngôn ngữ nào cũng hỗ trợ đầy đủ multi-processing.

3. CPU bound multi-thread hay multi-process?

3.1 Multitasking

Máy tính ngày nay CPU 4 lõi, 8 lõi (core)... luôn chạy nhiều chương trình cùng lúc. Máy tính ngày xưa khi chỉ có 1 CPU 1 core cũng vậy, chạy được nhiều chương trình "cùng lúc" nhờ CPU chuyển liên tục chạy các chương trình khác nhau, việc chuyển đổi rất nhanh này khiến người dùng có cảm giác là chạy cùng lúc. Ví dụ chạy 4 process A B C D:

A B C D A B D C B A C D...

chuyện này không thay đổi kể cả với máy tính nhiều core do số chương trình chạy luôn lớn hơn số core nhiều lần. Ví dụ:

$ grep -c processor /proc/cpuinfo
4
$ ps -ef | wc -l
265

PS: bạn đọc sau khi đọc xong command line linux nhé.

3.2 CPU Schedular

Việc sắp xếp các chương trình chạy thế nào (dùng CPU thế nào) do một bộ phận của kernel có tên "scheduler" thực hiện - Linux CPU scheduler Chi tiết mình sẽ đề cập trong bài viết sau.Tạm thời cứ biết vậy đã 😃

3.3 Một process chạy multi-thread trên mấy CPU Core?

Tham khảo tại man 7 sched

$ whatis sched
sched (7) - overview of CPU scheduling

Trong tài liệu viết:

Scheduling policies The scheduler is the kernel component that decides which runnable thread will be executed by the CPU next. Each thread has an associated scheduling policy and a static scheduling priority, sched_priority. The scheduler makes its decisions based on knowledge of the scheduling policy and static priority of all threads on the sys‐ tem.
API summary Linux provides the following system calls for controlling the CPU scheduling behavior, policy, and priority of processes (or, more precisely, threads).

Linux kernel scheduler sắp xếp lịch chạy trên CPU cho các thread (hay gọi là task).

Trong man 1 taskset viết:

-a, --all-tasks Set or retrieve the CPU affinity of all the tasks (threads) for a given PID.

Một process chạy multithreading trên mấy CPU core?

Với 10 process, mỗi process chỉ có 1 thread, sẽ là 10 thread cần chạy, kernel sẽ sched (xếp lịch) việc chạy 10 task này cho N CPU. Tương tự 1 process, chạy 10 thread, kernel cũng sẽ sched việc chạy 10 task này cho N CPU (N > 0).

Python multi-threaded vs multi-process Dòng thứ 2 trong tài liệu thư viện threading của Python viết

CPython implementation detail: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing or concurrent.futures.ProcessPoolExecutor. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.

Python là một trong số ít ngôn ngữ mà nhiều thread không chạy được trên nhiều CPU core cùng lúc do giới hạn của Global Interpreter Lock - GIL trong CPython/PyPy. Giới hạn này KHÔNG tồn tại trong các bản Python khác như Jython (trên JVM) và IronPython (trên .NET). Vì GIL, CPython chỉ có thể chạy trên CPU 1 thread 1 lúc, nên muốn chạy nhiều thread/process trên nhiều CPU core cùng lúc, Python có thư viện multiprocessing.

Multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine.

Tránh nhầm lẫn rằng python threading thực sự chạy các thread cùng lúc trên nhiều CPU core, việc các thread có vẻ chạy cùng lúc trong Python chỉ là multitasking, chạy chuyển đổi giữa các thread.

Java multithreading

Java hỗ trợ multithreading với các thread chạy cùng lúc như mong đợi, và nhiều thread này hoàn toàn có thể được chạy trên nhiều CPU core.

Vì multithreading chạy rất ngon lành, nên ít có lý do gì để sinh ra khái niệm "multiprocessing" như Python. Ngoài ra, bật 1 Java process là chạy 1 máy ảo JVM nặng nề, khởi động chậm (so với bật 1 process CPython interpreter 0.1s 8MB RAM) nên việc này rất ít thấy trong thực tế.

PS: Python threading API dựa trên API của Java.

Ngoài ra, trong Java 8 stream API có parallel stream thể hiện rõ đặc điểm của việc chạy multithread trên N core. Các bạn có thể xem chi tiết ở stackoverflow hoặc baeldung.

Rust multithreading

Tương tự Java, không tồn tại thư viện "multiprocessing" trong Rust.

In most current operating systems, an executed program’s code is run in a process, and the operating system will manage multiple processes at once. Within a program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. For example, a web server could have multiple threads so that it could respond to more than one request at the same time.

Go multithreading, multiprocessing

Go không dùng khái niệm process hay thread của hệ điều hành mà dùng khái niệm Goroutine, tương tự thread, nhưng do Go runtime quản lý thay vì OS kernel.

A goroutine is a lightweight thread managed by the Go runtime. Goroutines run in the same address space, so access to shared memory must be synchronized.

Các goroutine cũng có thể được nhiều CPU core chạy cùng lúc

GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting.

3.4 Kết luận

  • CPU bound là chương trình dành phần lớn thời gian dùng CPU xử lý, khác với
  • IO bound là chương trình dành phần lớn thời gian đọc ghi file/network.

Câu hỏi này có thể là trap, cần hỏi lại dùng ngôn ngữ gì, trừ khi hỏi cụ thể tới Python thì trả lời dùng multiprocessing. Trong các ngôn ngữ khác như Rust/Java, multithreading là câu trả lời, vì không có thư viện multi-process mà chạy. Hay Go chỉ có goroutine chứ không có lựa chọn khác.

Khi nói chung chung, multi-process có ưu điểm là sự tách biệt giữa các process, một process bị crash sẽ không ảnh hưởng tới process khác, nhược điểm là việc giao tiếp giữa các process để chia sẻ data sẽ phức tạp. Nhiều chương trình dùng mô hình này như:

  • postgresql
  • nginx master-workers

Multi-threaded giúp dễ dàng truy cập bộ nhớ chung, nhưng có thể gặp trường hợp 1 thread crash khiến cả chương trình tắt ngóm, nhược điểm là dễ xảy ra race-condition: N thread tranh nhau truy cập cùng 1 tài nguyên.

Không có câu trả lời dễ dàng, vì đây là trường hợp của PostgreSQL, sau vài chục năm chạy multi-process, nay đang khám phá option multi-thread.

Let's make PostgreSQL multi-threaded

Reference

After credit

Đón chờ bài viết sau về chủ đề Cách OS quản lý thread nhé!!!

Anh Tu Phi

Bình luận

Bài viết tương tự

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 218

- vừa được xem lúc

Go Concurrency qua các ví dụ (Phần 1): Dining Philosophers

Bài toán Dining Philosophers (Bữa tối của các triết gia) là một trong những bài toán kinh điển thường dùng để mô tả các vấn đề trong việc xử lý concurrent, những vấn đề thường gặp trong quá trình cấp

0 0 247

- vừa được xem lúc

Concurrent and Parallel 001: Parallel computing hardware P1

Bài viết nằm trong series Concurrent vs Parallel in Java. 1) Sequential vs Parallel computing.

0 0 50

- vừa được xem lúc

Concurrent and Parallel 006: Vòng đời của một thread diễn ra như thế nào trong Java?

Bài viết nằm trong series Multithread từ hardware tới software với Java. Thread lifecycle.

0 0 56

- vừa được xem lúc

005: OS đối xử với thread thế nào?

Bài viết nằm trong series Multithread từ hardware tới software với Java. 1) Schedular.

0 0 33

- vừa được xem lúc

003: Thread và Process

Bài viết nằm trong series Multithread từ hardware tới software với Java. .

0 0 38