thảo luận Javascript có thực sự là single thread ?

  • Người tạo chủ đề Người tạo chủ đề teeeeeeeee
  • Ngày bắt đầu Ngày bắt đầu
Multi thread không hản là hai thread cùng access một đoạn code. Như mình nói hồi nãy, sử dụng event driven hoặc như function programming immutable hết là xong.
immutable của FP là language feature, mỗi lần update data là nó tạo copy mới (tất nhiên nó có thể share một phần dữ liệu cũ), trong nhiều bài toán thì nó là overhead không thể chấp nhận được. cho nên implement language runtime không ai dùng immutable structure cả.

cơ mà dù là dùng immutable tất cả nhé, thì cái pointer/reference tới đoạn dữ liệu ấy có phải là mutable không, lockup address có phải là mutable không? cuối cùng thì bên dưới đáy nó vẫn phải implement mấy cái ở trên đang thảo luận thôi.
 
à không, mutex thường chỉ xảy ra lúc ghi thôi, với lại tuỳ loại mutex, nó không block hẳn đâu.
với lại cũng tuỳ cách bạn thiết kế nữa, dùng 1 channel hay dùng nhiều channel kết hợp để lưu shared memory.
Ừa, nó sẽ thường xảy ra lúc ghi, nên mình mới nói về bài toán update cùng lúc.
Ngoài ra, về bài toán read, thì phải check xem có đang lock update không thì mới read local được.

Còn bài toán của bác Prescot, thì thường người ta dùng CAS thôi. Chứ chẳng ai dùng mutex block cả. Tuy nhiên, mình đang muốn lấy ví dụ, về cách có thể không cần share memory.

Mà không block hẳn là sao bác nhỉ.
 
immutable của FP là language feature, mỗi lần update data là nó tạo copy mới (tất nhiên nó có thể share một phần dữ liệu cũ), trong nhiều bài toán thì nó là overhead không thể chấp nhận được. cho nên implement language runtime không ai dùng immutable structure cả.

cơ mà dù là dùng immutable tất cả nhé, thì cái pointer/reference tới đoạn dữ liệu ấy có phải là mutable không, lockup address có phải là mutable không? cuối cùng thì bên dưới đáy nó vẫn phải implement mấy cái ở trên đang thảo luận thôi.
Mỗi bài toán có một architect khác nhau phù hơp. Vấn đề là, bác Prescot cho rằng không tồn tại Concurrency non share memory.
Còn immutable của FP không phải như bác nói đâu, nó là cách thiết kế code thôi, cố gắng chuyển dịch code từ xử lý data chung thành những process, mỗi process là một pure function không gây side effect mà chỉ quan tâm tới input và output. Nó không dùng cho mọi bài toán, nhưng là một cách thiết kế.
Ví dụ, như bài toán của bác Prescot, FP sẽ thiết kế như này. Read ips từ Redis, gọi function update, chờ kết quả, call function save redis với kết quả nhận được.
Điểm mạnh của thiết kế này là tăng tính independent giữa các thread, thuận tiện để xử lý parralel hơn. Bác biết mà, share memory là kẻ thù của parralel.
Parralel chứ không phải Concurrency.
 
Ghi vào redis là phía tool hay frontend, phần mềm ko có write gì trong này cả, chỉ đọc thôi.
Vài khi đọc thì sẽ flush shared memory, thread nào nhận packet có destination 1.1.1.1 trước và expire time tới hạn thì sẽ update shared memory pool tương ứng 1.1.1.1, trong qua trình update thì mấy thread còn lại nếu cũng nhận 1.1.1.1 thì dữ liệu sẽ rỗng luc đó thì sẽ có bảng memory của riêng thread đọc từ file lên, như vậy sẽ giải quyết được vấn đề block ở shared mem. Nếu lúc nào cũng đọc file thì block cao hơn, và đọc từ file thì không có timeout như đọc từ TCP, io mà dẹo thì rất dễ dead lock
Bác có biết thiên kiến của bác là gì không? Bác cho răng một Architect là tốt nhất, và bác cũng đang lấy ví dụ về thứ thân thuộc với bạn nhất, một bài toán mà bác hiểu rõ về requirement để lấy ví dụ, đúng không? Và như mình đã nói, có rất nhiều cách để handle concurrency. Không nhất thiết phải share memory.
Và câu chuyện gom lại là về cách thiết kế thôi. Bác Nipin nói bác đi lạc để ngay từ đầu đó, mình cũng muốn hầu với bác.
Trở lại với bài toán, block cao hơn có nghĩa là gì? Vì sao nếu mấy thread còn lại nhận 1.1.1.1 thì dữ liệu sẽ rỗng? Bảng memory đọc từ file lên, file đó bác lưu ở đâu vậy? Nếu mình muốn 64 thread là phải tạo ra 64 file à, vì sao làm vậy thì giải quyết được block từ share mem? Share mem làm sao bị block được, ý bác là những action với share mem đó hở? Action cự thể la read hay write?
Bài toán của mình là 32 thread cùng update cùng lúc, vì mình không hiểu bác đang nói gì, nên mình gom lại bài toán như vậy. Lúc đó, bác xử lý như nào?
 
Còn nếu ý bác đang nói về share memory mà bác share, thì thưa bác, có hai điều.
Thứ nhất, đó là share memory của system, không phải là share memory khi thiết kế concurrency.
Thứ hai, Golang là multiple thread language, và architect của nó không có share memory ở system bác ạ. Mỗi goroutine không dùng chung stack, thưa bác.
 
Ừa, nó sẽ thường xảy ra lúc ghi, nên mình mới nói về bài toán update cùng lúc.
Ngoài ra, về bài toán read, thì phải check xem có đang lock update không thì mới read local được.

Còn bài toán của bác Prescot, thì thường người ta dùng CAS thôi. Chứ chẳng ai dùng mutex block cả. Tuy nhiên, mình đang muốn lấy ví dụ, về cách có thể không cần share memory.

Mà không block hẳn là sao bác nhỉ.
Về nguyên tắc update cái gì liên quan tới network, file là có io block, mutex lock tài nguyên A thì các thread khác sẽ không truy cập được trong thời gian đó, tức là nó sẽ sleep, để giải quyết vấn đề này vói nhưng share mem liên quan tới io block thì có một giải pháp tôi thiết kế phải sét loại giá trị đó hạn sử dụng theo timestamp của OS để tránh update liên tuc
- Các thread còn lại tránh bi sleep waiting khi A đang bi mutex lock thi sử dụng hàm có sẵn trong linux kernel để check có đang lock hay ko https://elixir.bootlin.com/linux/v4.4.137/source/include/linux/mutex.h#L128
, nếu lock thì thread đọc từ file lên, file có thể nằm trong RAm disk hay bất kỳ cái nào có io cao.
mà những cái này thi mấy ngôn ngữ cấp cao không thể làm được :haha:
 
Về nguyên tắc update cái gì liên quan tới network, file là có io block, mutex lock tài nguyên A thì các thread khác sẽ không truy cập được trong thời gian đó, tức là nó sẽ sleep, để giải quyết vấn đề này vói nhưng share mem liên quan tới io block thì có một giải pháp tôi thiết kế phải sét loại giá trị đó hạn sử dụng theo timestamp của OS để tránh update liên tuc
- Các thread còn lại tránh bi sleep waiting khi A đang bi mutex lock thi sử dụng hàm có sẵn trong linux kernel để check có đang lock hay ko https://elixir.bootlin.com/linux/v4.4.137/source/include/linux/mutex.h#L128
, nếu lock thì thread đọc từ file lên, file có thể nằm trong RAm disk hay bất kỳ cái nào có io cao.
mà những cái này thi mấy ngôn ngữ cấp cao không thể làm được :haha:
Ồ, tức là bài toán của bác là. Mình sẽ tóm gọn bài toán này lại. Bác muốn xử lý concurrent để Read một trạng thái whiteIP với delay time nhỏ nhất, để đảm bảo Read liên tục, Write sẽ rất hạn chế. Đúng không.
Lời giải của bác, là read phải check lock, nếu lock thì phải đọc từ file lên.
Vậy, bác update file local như nào hở bác? Mỗi lần thực thiện process đều compare với srm để update, hay mỗi lần check lock xong phải đọc từ file local, sau đó quay lại đọc từ srm để update local file, hay thực hiện cron update?
Ấy bác ạ, mấy ngôn ngữ cấp cao làm giúp mình phần check lock rồi bác ạ. Và các bài toán của ngôn ngữ cấp cao khác bài toán mà bác giải quyết nhiều lắm. TUy nhiên, em vẫn muốn hầu bác.
 
Ồ, tức là bài toán của bác là. Mình sẽ tóm gọn bài toán này lại. Bác muốn xử lý concurrent để Read một trạng thái whiteIP với delay time nhỏ nhất, để đảm bảo Read liên tục, Write sẽ rất hạn chế. Đúng không.
Lời giải của bác, là read phải check lock, nếu lock thì phải đọc từ file lên.
Vậy, bác update file local như nào hở bác? Mỗi lần thực thiện process đều compare với srm để update, hay mỗi lần check lock xong phải đọc từ file local, sau đó quay lại đọc từ srm để update local file, hay thực hiện cron update?
Ấy bác ạ, mấy ngôn ngữ cấp cao làm giúp mình phần check lock rồi bác ạ. Và các bài toán của ngôn ngữ cấp cao khác bài toán mà bác giải quyết nhiều lắm. TUy nhiên, em vẫn muốn hầu bác.
shm có thì xài, ko có thì đọc từ file. local file có nội dung song song với redis được ghi từ service khác độc lập . Đọc tự file lên cũng chỉ mất vài chục của phần triệu s và cũng chỉ đọc khi mutex_lock, và đọc xong thì cũng lưu vào thread mem để xài lại.
 
Sửa lần cuối:
shm có thì xài, ko có thì đọc từ file. local file có nội dung song song với redis được ghi từ service khác độc lập . Đọc tự file lên cũng chỉ mất vài chục của phần triệu s và cũng chỉ đọc khi mutex_lock
Thật ra
shm có thì xài, ko có thì đọc từ file. local file có nội dung song song với redis được ghi từ service khác độc lập . Đọc tự file lên cũng chỉ mất vài chục của phần triệu s và cũng chỉ đọc khi mutex_lock, và đọc xong thì cũng lưu vào thread mem để xài lại.
Đọc xong lưu vào thread mem để xài lại là sao bác nhỉ, bác đọc từ file ra rồi lưu lại vào file à. Service khác độc lâp tức là phải cron task đúng khônng, hay là listen event khi có write vào redis.
Và bài toán chính ở đây là, làm sao để đọc nhanh nhất có thể thôi, đúng hem bác.
 
Có thể dùng một ngôn ngữ C hay Java để viết mô phỏng lại event loop của node js muc đích concurrency mà chạy được đa luồng. Mutithread, mỗi thread muti concurrency, non blocking. Hàng mì ăn liền thì nó tới đó thôi
vâng nói chung về mặt nguyên lý, khi nắm đc mô hình thì có thể mô phỏng lại được. ví dụ ở đây NodeJS phải lưu ý mấy cái run-to-complete, scheduling, message queues cho workers, triển khai cụ thể ra thì phải xem tính năng của host language. đoán chừng cũng nhiều việc. Với mình thì tinh thần là right tool right job như bác gì nói ở trên. Mô hình concurrency, languages/frameworks hỗ trợ cũng đầy ra.
ps. chém với các bác cho vui chứ mình amateur
 
mà những cái này thi mấy ngôn ngữ cấp cao không thể làm được :haha:
  • Trên đời nàycó bao nhiêu ngôn ngữ bật cao?
  • Anh biết đc bao nhiêu, đã code đc bao nhiêu ngôn ngữ?
  • Anh từng làm bao nhiêu hệ thống, bao nhiêu cấu trúc phần cứng, mềm?

Tôi không biết ông anh trình thế nào, nhưng phát biểu câu này thì ông anh tự phụ và hẹp hòi lắm :D
 
  • Trên đời nàycó bao nhiêu ngôn ngữ bật cao?
  • Anh biết đc bao nhiêu, đã code đc bao nhiêu ngôn ngữ?
  • Anh từng làm bao nhiêu hệ thống, bao nhiêu cấu trúc phần cứng, mềm?

Tôi không biết ông anh trình thế nào, nhưng phát biểu câu này thì ông anh tự phụ và hẹp hòi lắm :D
Đây có phải bài trắc nghiệm các câu hỏi mẩu giáo không.

via theNEXTvoz for iPhone
 
Thật ra

Đọc xong lưu vào thread mem để xài lại là sao bác nhỉ, bác đọc từ file ra rồi lưu lại vào file à. Service khác độc lâp tức là phải cron task đúng khônng, hay là listen event khi có write vào redis.
Và bài toán chính ở đây là, làm sao để đọc nhanh nhất có thể thôi, đúng hem bác.
Là luu vào bộ nhớ của riêng cái thread đó. Service khác tu frontend ghi vào là thao tác của user. Sau khi ghi vào redis hay file thì thôi là xong của frontend, phần còn lại là firewall tự cập nhật, sẽ ko có event gì cả

via theNEXTvoz for iPhone
 
Là luu vào bộ nhớ của riêng cái thread đó. Service khác tu frontend ghi vào là thao tác của user. Sau khi ghi vào redis hay file thì thôi là xong của frontend, phần còn lại là firewall tự cập nhật, sẽ ko có event gì cả

via theNEXTvoz for iPhone
Vấy phía 32 threads đọc , thím làm sao để đồng bộ data thay đổi ?

Đọc thì có vẻ data của các chấp nhận chuyện xảy ra inconsistent ( trong thời gian chờ expire của bác) giữa dữ liệu thật trên redis và cache trên mem của từng thread. Vì theo bác nói tác vụ ghi và đọc ko đồng bộ respect lẫn nhau
 
Sửa lần cuối:
Thật ra

Đọc xong lưu vào thread mem để xài lại là sao bác nhỉ, bác đọc từ file ra rồi lưu lại vào file à. Service khác độc lâp tức là phải cron task đúng khônng, hay là listen event khi có write vào redis.
Và bài toán chính ở đây là, làm sao để đọc nhanh nhất có thể thôi, đúng hem bác.
Thôi được rồi, mình nói mà bác không rep nữa thì thôi vậy.

Điểm yếu của share memory là, bác phải handle được bài toán deadlock, race condition, live lock..., Không thể chạy parallel, vì bác bị phụ thuộc vào share memory, bắt buộc các tác vụ của bác phải chạy trên một thread. Xu hướng xử lý performance bây giờ là, tối ưu core, cách hiện thực là, chia task nhỏ ra không phụ thuộc lẫn nhau, để có thể phân đều cho core xử lý. Ví dụ một tác vụ 3 bước trên cùng một thread, thì chỉ có một core xử lý, nhưng nếu tách tác vụ đó ra 3 step riêng biệt, phân vào 3 thread, để 3 thread xử lý, thì có khả năng bác sẽ được 3 core xử lý. Ví dụ như action firewall của bác, có 3 step là xử lý trước khi đọc shm, đọc shm, và xử lý sau khi đọc shm. Nếu bác không dùng shm, bác có thể chia nó ra làm 3 task riêng biệt.
Để thiết kế hoàn chỉnh thì rất dài, nên mình đã đưa cách đơn giản, dựa theo idea trên, đẩy tác vụ xử lý storage vào một thread riêng.
Nhưng điểm chính yếu mình muốn nói với bác, đó là tồn tại architect concurrency non share memory. Và điểm thứ hai là, không có công nghệ nào là tốt nhất.
Nên mong bác đừng áp đặt, đừng chê bai, cũng đừng tự cho mình là đúng. Học hỏi cùng phát triển mới là cách để mỗi người làm công nghệ phát triển.
 
Vấy phía 32 threads đọc , thím làm sao để đồng bộ data thay đổi ?
Tôi thiết kế kiểu dữ liệu như sau
Ip destination: a sẽ có acl là b
Acl b có một time expire là 30s từ lần update trước đó theo tham chiếu time của os
Khi gói tin có des là a vào thì sẽ tham chiếu acl b, nếu thơi gian trong b lúc tham chiếu đã expire thì flush và update smember từ redis và ghi vào shm, ngược lại nếu chưa quá hạn thì lấy ip ra và đối sánh với a. Nếu acl b trong suốt thời gian ko có packet a đi vào thì sẽ ko bao giờ cần phải update vì acl b không được tham chiếu

via theNEXTvoz for iPhone
 
Thôi được rồi, mình nói mà bác không rep nữa thì thôi vậy.

Điểm yếu của share memory là, bác phải handle được bài toán deadlock, race condition, live lock..., Không thể chạy parallel, vì bác bị phụ thuộc vào share memory, bắt buộc các tác vụ của bác phải chạy trên một thread. Xu hướng xử lý performance bây giờ là, tối ưu core, cách hiện thực là, chia task nhỏ ra không phụ thuộc lẫn nhau, để có thể phân đều cho core xử lý. Ví dụ một tác vụ 3 bước trên cùng một thread, thì chỉ có một core xử lý, nhưng nếu tách tác vụ đó ra 3 step riêng biệt, phân vào 3 thread, để 3 thread xử lý, thì có khả năng bác sẽ được 3 core xử lý. Ví dụ như action firewall của bác, có 3 step là xử lý trước khi đọc shm, đọc shm, và xử lý sau khi đọc shm. Nếu bác không dùng shm, bác có thể chia nó ra làm 3 task riêng biệt.
Để thiết kế hoàn chỉnh thì rất dài, nên mình đã đưa cách đơn giản, dựa theo idea trên, đẩy tác vụ xử lý storage vào một thread riêng.
Nhưng điểm chính yếu mình muốn nói với bác, đó là tồn tại architect concurrency non share memory. Và điểm thứ hai là, không có công nghệ nào là tốt nhất.
Nên mong bác đừng áp đặt, đừng chê bai, cũng đừng tự cho mình là đúng. Học hỏi cùng phát triển mới là cách để mỗi người làm công nghệ phát triển.
Race condition và dead lock là do bạn code không đúng đẻ dead lock, đó ko phải là vướng mắt. Người ta sinh ta mutex đẻ tranh race condition và việc bạn khoá mutex không đúng làm deadlock là vấn đề chủ quan không phải giới hạn ky thuật. Nếu bạn chạy chỉ một thread thì với ứng dụng cấp hệ thống như tôi trình bày thì sẽ ko thể nào sủ dụng hết được interrupt và numa node. Đây là sản phẩm đang chạy production, có user chứ ko phải tôi nghĩ ra
Ví du trang mxh này, dĩ nhiên fw chay nhiều trang chứ ko phải một
Lazi.vn traffic một tháng 5 triêu kh dang sử dụng fw ở trên. Nói chung khi nào ban viết ứng dụng chạy dưới hệ thống cap thap thì bạn mới hiểu kiểu chia nhỏ micro, nhiều dependence càng làm cho hệ thống sinh nhiêu single point of failture. Là việc không cần thiết

via theNEXTvoz for iPhone
 
Tôi thiết kế kiểu dữ liệu như sau
Ip destination: a sẽ có acl là b
Acl b có một time expire là 30s từ lần update trước đó theo tham chiếu time của os
Khi gói tin có des là a vào thì sẽ tham chiếu acl b, nếu thơi gian trong b lúc tham chiếu đã expire thì flush và update smember từ redis và ghi vào shm, ngược lại nếu chưa quá hạn thì lấy ip ra và đối sánh với a. Nếu acl b trong suốt thời gian ko có packet a đi vào thì sẽ ko bao giờ cần phải update vì acl b không được tham chiếu

via theNEXTvoz for iPhone
Ok thím.

Hiện tại trên cache data của thread đọc chứa 1 entry ip a có acl là b như thím nói nha. Và còn tận 20s nữa mới expire.

Ngay lúc đó bên write thì thay đổi remove 1 entry này đi. Vì bác ko có cơ chế nào đồng bộ cho bên read. Nên bọn read phải sau khi expire mới thấy đc sự thay đổi.


Vậy thì có vẻ data của các chấp nhận chuyện xảy ra inconsistent ( trong thời gian chờ expire của bác) giữa dữ liệu thật trên redis và cache trên mem của từng thread. Vì theo bác nói tác vụ ghi và đọc ko đồng bộ respect lẫn nhau

via nextVOZ for iPhone
 
Ok thím.

Hiện tại trên cache data của thread chứa 1 entry ip a có acl là b như thím nói nha. Và còn tận 20s nữa mới expire.

Ngay lúc đó bên write thì thay đổi remove 1 entry này đi. Vì bác ko có cơ chế nào đồng bộ cho bên read. Nên bọn read phải sau khi expire mới thấy đc sự thay đổi.


Vậy thì có vẻ data của các chấp nhận chuyện xảy ra inconsistent ( trong thời gian chờ expire của bác) giữa dữ liệu thật trên redis và cache trên mem của từng thread. Vì theo bác nói tác vụ ghi và đọc ko đồng bộ respect lẫn nhau

via nextVOZ for iPhone
Chính xác là như vậy max là 30s, tuy nhiên nếu user vừa add hay vùa xoá ngay lúc có traffic đi vào và đúng time expire thì nó tức thời, nên 30s chỉ là lâu nhất, thúc tế mình cho 5s vẫn ok vẫn mượt mà nhưng mình không thích day he thong tới hạn, và kh chấp nhận nó :haha:

via theNEXTvoz for iPhone
 
Vấy phía 32 threads đọc , thím làm sao để đồng bộ data thay đổi ?

Đọc thì có vẻ data của các chấp nhận chuyện xảy ra inconsistent ( trong thời gian chờ expire của bác) giữa dữ liệu thật trên redis và cache trên mem của từng thread. Vì theo bác nói tác vụ ghi và đọc ko đồng bộ respect lẫn nhau
Cái này thím ấy có nói rồi
Race condition và dead lock là do bạn code không đúng đẻ dead lock, đó ko phải là vướng mắt. Người ta sinh ta mutex đẻ tranh race condition và việc bạn khoá mutex không đúng làm deadlock là vấn đề chủ quan không phải giới hạn ky thuật. Nếu bạn chạy chỉ một thread thì với ứng dụng cấp hệ thống như tôi trình bày thì sẽ ko thể nào sủ dụng hết được interrupt và numa node. Đây là sản phẩm đang chạy production, có user chứ ko phải tôi nghĩ ra
Ví du trang này
Lazi.vn traffic một tháng 5 triêu kh dang sử dụng fw ở trên

via theNEXTvoz for iPhone
Vướng mắc chứ bác, vì race condition, dead lock..., nó không nằm ở những tác vụ đơn giản, mà có những case phức tạp hơn nhiều, mà ở đó, để handle tốt, bác sẽ phải đánh đổi performance, cả ở sản phẩm và thời gian release sản phẩm. Thứ hai, là khả năng scale up, khi hệ thống bác bị phụ thuộc lẫn nhau, logic xử lý cồng kềnh ( ở đây là logic xử lý race condition...), scale up là tốn effort. Scale up tức là thêm logic á, thêm requirements á, chứ mình chưa nói đến scale hệ thống.
Nên người ta mới nghĩ ra những phương pháp giảm bớt sự phụ thuộc.
Bác đừng định kiến nhé, môt giải pháp chạy tốt cho một ứng dụng 5tr user chưa chắc dùng được cho ứng dụng khác. Ngay từ đầu mình đã nói concurrency share memory là một trong những cách thực thi concurrency mà. Mình không phủ nhận nó. Nhưng vẫn còn những giải pháp khác. Nên mong bác đừng đưa ra một thực tiễn để loại bỏ hoàn toàn lý thuyết.
 

Thống kê chủ đề

Ngày tạo
teeeeeeeee,
Người trả lời cuối
AnyaKyle,
Trả lời
199
Lượt xem
30.126
Quay lại
Lên đầu trang