Nội dung bài viết
Concurrency là gì?
Concurrency (tính đồng thời) là khả năng xử lí nhiều tác vụ cùng 1 lúc. Ví dụ, khi bạn đang lướt web, có thể bạn đang download file trong khi đang nghe nhạc, đồng thời đang scroll trang. Nếu trình duyệt không thể thực hiện chúng cùng 1 lúc, bạn sẽ phải đợi đến khi mọi file download xong, mới có thể nghe nhạc, rồi mới có thể scroll. Điều này nghe rất khó chịu phải không nào?Vậy làm thế nào để 1 máy tính có CPU 1 nhân có thể xử lí nhiều tác vụ cùng lúc, trong khi 1 nhân CPU chỉ có thể xử lí 1 việc tại 1 thời điểm? Concurrency tức là xử lí 1 tác vụ tại 1 thời điểm, nhưng CPU không xử lí hết 1 tác vụ rồi mới đến tác vụ khác, mà sẽ dành 1 lúc cho tác vụ này, 1 lúc cho tác vụ kia. Do vậy, chúng ta có cảm giác máy tính thực hiện nhiều tác vụ cùng 1 lúc, nhưng thực chất chỉ có 1 tác vụ được xử lí tại 1 thời điểm.Cùng xem biểu đồ dưới để rõ hơn về cách CPU phân bố khi chúng ta sử dựng web ở ví dụ trên.
Đang xem : Concurrent là gì
Bạn đang đọc: Concurrent Là Gì – Nghĩa Của Từ Concurrent
Từ biểu đồ trên, tất cả chúng ta hoàn toàn có thể thấy rằng, CPU 1 nhân phân loại thời hạn thao tác dựa trên độ ưu tiên của cùng tác vụ. Ví dụ, khi đang scroll trang, việc nghe nhạc sẽ có độ ưu tiên thấp hơn, nên hoàn toàn có thể nhạc của bạn sẽ bị dừng do đường truyền kém, nhưng bạn vẫn hoàn toàn có thể kéo trang lên xuống .
Parallelism là gì?
Ở phần trên, tất cả chúng ta chỉ nói về CPUí 1 nhân, nhưng nếu máy tính có CPU nhiềunhân thì sao ? Với ví dụ lượt web, CPU 1 nhân cần chia thời hạn sử dụng cho những tác vụ. Còn với CPU nhiều nhân, tất cả chúng ta hoàn toàn có thể xử lí nhiều tác vụ cùng lúc trên những nhân khác nhau ?
Cơ chế xử lí nhiều tác vụ song song với nhau được gọi làparallelism. Khi CPU có nhiều nhân, tất cả chúng ta hoàn toàn có thể sử dụng nhiều nhân để xử lí nhiều thứ 1 lúc .
Concurrency vs Parallelism
Go khuyến khích việc sử dụnggoroutineschỉ trên 1 nhân, tuy nhiên, tất cả chúng ta cũng hoàn toàn có thể chỉnh sửa đểgoroutineschạy trên những nhân khác nhau. Có thể coigoroutineslà 1 function trong go. Có vài điểm độc lạ giữa concurrency và parallelism. Concurrency xử lí nhiều 1 tác vụ 1 lúc, còn parallelism là thực thi nhiều tác vụ cùng 1 lúc. Parrallism không phải khi nào cũng tốt hơn concurrency. Chúng ta sẽ điều tra và nghiên cứu sâu hơn về yếu tố này trong những bài viết tới. Để hiểu rõ hơn về concurrency trong go và cách sử dụng chúng trong code, trước hết tất cả chúng ta cần hiểu hơn về 1 tiến trình xử lí ( process ) của máy tính .
Proccess của máy tính là gì?
Khi viết 1 chương trình máy tính bằng ngôn từ như C, Java, hay Go, thì về cơ bản chúng cũng chỉ là file văn bản. Còn máy tính chỉ hiểu code dạng binary. Do vậy tất cả chúng ta cần biên dịch code ra ngôn từ máy. Khi 1 chương trình đã được biên dịch được gửi đến OS ( hệ quản lý ) để xử lí, hệ quản lý và điều hành sẽ cấp cho 1 khoảng trống bộ nhớ, 1 bộ đếm chương trình, PID ( process id ) và nhiều thứ khác. 1 process có tối thiểu 1 thread được gọi là thread chính, và thread chính hoàn toàn có thể tạo nhiều nhiều thread khác. Khi thread chính hoàn thành xong, process sẽ biến mất. Nói chung, tất cả chúng ta hoàn toàn có thể hiểu rằng 1 process sẽ gồm có đoạn code đã được biên dịch, bộ nhớ, những tài nguyên của hệ điều hành quản lý và nhiều thứ khác được phân phối cho thread .
Thread là gì?
Thread giống như process, nhưng nó là 1 thực thể nằm trong process. Thread hoàn toàn có thể truy câp đến bộ nhớ được phân phối bởi process, tài nguyên của hệ quản lý và những thứ khác. Khi thực thi 1 đoạn code, thread sẽ lưu biến ( tài liệu ) và trong 1 vùng nhớ được gọi làstack. Stackđược tạo ra vào thời hạn biên dịch, và nó thường có kích cỡ cố định và thắt chặt, từ 1-2 MB.Stackcủa 1 thread chỉ được sử dụng trong thread đó. Heaplà 1 thuộc tính của process và nó hoàn toàn có thể được truy vấn từ mọi thread trong process đó. Heap là 1 vùng nhớ được chia sẽ giữa những thread với nhau. Vậy khi nào thread được sử dụng ? Ví dụ, khi lướt web, phải có 1 đoạn code nào đó hướng dẫn cho hệ quản lý và điều hành xử lí. Điều đó có nghĩa là tất cả chúng ta đang tạo ra 1 process. Khi 1 tab mới được mở ra, trong khi tất cả chúng ta đang sử dụng, proccess cho tab sẽ khởi đầu tạo ra nhiều thread khác nhau cho những hành vi khác nhau ( như tải về, nghe nhạc, .. ) .
Ở ảnh trên, hoàn toàn có thể thấy ngay rằng Google Chrome đang sử dụng nhiều process cho những tab và những tác vụ ngầm. Mỗi process có tối thiểu 1 thread, ở ví dụ trên, 1 process của Chrome thường có đến hơn 10 thread. Ở những phần trên, tất cả chúng ta đã nói về việc xử lí nhiều việc và triển khai nhiều viêc 1 lúc. Việc ở đây là những hành vi triển khai bởi 1 thread. Do vậy, khi nhiều việc được được triển khai theo kiểu đồng thời hoặc song song, tương ứng sẽ có nhiều thread chạy đồng thời hoặc song song, hay còn gọi là multi-threading. Khi nhiều thread được sinh ra bởi 1 process, và 1 thread gây tràn bộ nhớ ( memory leak ), sẽ khiến cho process bị đơ, và tất cả chúng ta phải dùng task manager để tắt nó. Khi nhiều thread cùng chạy đồng thời hoặc song song, do có nhiều thread cùng chia sẽ tài liệu chung, nên chúng cần phối hợp uyển chuyển để làm thế nào chỉ 1 thread hoàn toàn có thể truy vấn vào 1 dữ liệu đơn cử tại 1 thời gian. OS thread được quản lí bởi kernel, 1 vài thread được quản lí bởi thiên nhiên và môi trường chạy ngôn từ. Nếu nhiều thread cùng biến hóa 1 dữ liệu tại cùng 1 thời gian, thì hiệu quả trả về năng lực cao không được như mong đợi, và gây rarace condition .
Concurrency trong Go
Ở những ngôn từ truyền thống lịch sử, ví dụ như Java, sẽ có 1 thread class để sử dụng khi cần tạo nhiều thread trong 1 process. Tuy nhiên, Go không có những cấu trúc cú pháp OOP truyền thống lịch sử, mà thay vào đó, Go phân phối từ khóagođể tạo ra cácgoroutines. Khi tất cả chúng ta gọi 1 function với từ khóagoở trước, nó sẽ trở thành 1 goroutines. Khi tất cả chúng ta chạy 1 chương trình, go runtime sẽ tạo ra 1 vài thread trên 1 nhân. 1 thread sẽ thực thi 1 goroutine, và khi goroutine đó bị khóa, 1 goroutine khác sẽ được thế vào và thực thi trên thread đó. Go khuyến khích việc sử chạy những goroutines chỉ trên 1 nhân CPU, tuy nhiêu nếu cần sử dụng nhiều nhân hơn, tất cả chúng ta hoàn toàn có thể sử dụng biến môi trườngGOMAXPROCShoặc sử dụng functionruntime. GOMAXPROCS ( n ) với n là số nhân muốn sử dụng. Tuy nhiên, đôi lúc bạn sẽ cảm thấy việc chạy trên nhiều nhân lại khiến chương trình của tất cả chúng ta chậm hơn. Trong trong thực tiễn, những chương trình mà sử dụng nhiều thời hạn để tương tác giữa những kênh ( channels ) hơn là việc đo lường và thống kê, sẽ cho hiệu suất tồi hơn khi sử dụng nhiều nhân CPU, OS process và thread .
Threads vs Goroutines
Thread |
Goroutines |
OS thread được quản lí bởi kernel và phụ thuộc vào phần cứng. |
Goroutines được quản lí bởi go runtime và không phụ thuộc vào vào phần cứng . Xem thêm : Top # 1 Tải trò chơi 7 Viên Ngọc Rồng Phiên Bản Mới Nhất Miễn Phí |
OS thread thường có kích cỡ stack cố định và thắt chặt từ 1-2 MB | Goroutines có kích cỡ stack từ 8KB |
Kích cỡ stack được xác lập trong thời hạn compile và không được tăng thêm . | Kích cỡ stack hoàn toàn có thể tăng đến 1GB |
Khó tương tác giữa những thread. Có độ trễ lớn trong việc tương tác giữa những thread . | Goroutine sử dụng channels để tương tác với nhau với độ trễ thấp |
Thread có định danh . | Goroutines không có định danh |
Thread mất nhiều thời hạn để tạo và xóa, do 1 thread cần nhiều tài nguyên từ hệ quản lý, và trả lại nó khi hoàn thành xong việc làm . | Goroutines được tạo và xóa bởi go runtime. Các hành vi này chạy nhẹ hơn nhiều so với thread, do go runtime luôn duy trì 1 lượng thread for goroutines . |
Để hiểu được sức mạnh của go concurrency, thử tưởng tượng tất cả chúng ta có 1 web server, mà phải xử lí 1000 request mỗi phút. Nếu phải chạy mỗi request đồng thời, tức là tất cả chúng ta cần tạo ra 1000 thread hoặc chia chúng ra những process khác nhau. Đây là cách mà Apache server quản lí những request. Nếu 1 OS thread chiếm 1MB cho stack của mỗi thread, thì tổng số tất cả chúng ta sẽ mất đến 1GB RAM. Apache cung cấpThreadStackSizeđể quản lí dung tích cho stack của mỗi thread, tuy nhiên nó cũng không xử lý được triệt để yếu tố .
Còn với goroutines, do dung tích stack tăng tự động hóa, tất cả chúng ta hoàn toàn có thể chạy đến 1000 goroutines mà không xảy ra yếu tố nào. Tuy nhiên, nếu có 1 chương trình chạy 1 hàm đệ quy cần nhiều bộ nhớ hơn, go hoàn toàn có thể tăng stack lên đến 1GB ( điều mà có lẽ rằng hiếm khi xảy ra, trừ khi với vòng lặp for { } chạy vô tận ). Để hiểu được sức mạnh của go concurrency, thử tưởng tượng tất cả chúng ta có 1 web server, mà phải xử lí 1000 request mỗi phút. Nếu phải chạy mỗi request đồng thời, tức là tất cả chúng ta cần tạo ra 1000 thread hoặc chia chúng ra những process khác nhau. Đây là cách mà Apache server quản lí những request. Nếu 1 OS thread chiếm 1MB cho stack của mỗi thread, thì tổng số tất cả chúng ta sẽ mất đến 1GB RAM. Apache cung cấpThreadStackSizeđể quản lí dung tích cho stack của mỗi thread, tuy nhiên nó cũng không xử lý được triệt để yếu tố .
Goroutines bị block khi gặp1 trong những trường hợpsau :
network inputdùng time sleepdùng channelsử dụng sync package
Channelsđóng vai trò quan trọng khi sử dụng goroutines. Chúng giúp ngăn ngừa race condition và việc truy vấn không đúng đến những tài liệu được san sẻ tựa như như ở thread .
Xem thêm : Đặc Điểm Ưu Việt Của Bộ Chăn Ga Gối Đệm Hanvico 2018, Chăn Ga Gối Đệm » Hanvico
Bài viết được dịch từhttps : / / medium.com/rungo/achieving-concurrency-in-go-3f84cbf870ca .
Source: https://swing.com.vn
Category: Wiki