Hướng dẫn php coroutine example
Chào các bạn, hôm nay chúng ta sẽ cùng nói một chút về xử lý bất đồng bộ và các vấn đề của nó Ví dụ chúng ta có đoạn code sau
Đối với các ngôn ngữ đồng bộ như PHP, Java, đoạn code trên sẽ được thực thi tuần tự từ trên xuống dưới. Kết quả sẽ có dạng
Chúng ta đều thấy có một vấn đề rằng, việc gọi tác vụ I/O (Gửi HTTP Request đến example.com) có thể tốn nhiều thời gian. Nếu có thể xử lý song song trong thời gian gửi Request thì sẽ có thể nâng performance hệ thống lên khá nhiều. MultiprocessingCác process được khởi tạo và quản lý bởi hệ điều hành OS. Các process độc lập với nhau về tài nguyên hệ thống (Ví dụ bộ nhớ).
Cách xử lý như trên gọi là Concurrency
(Mình gọi là đồng thời). Hiện tại hầu hết máy tính đều có nhiều hơn 1 core CPU, nên các tác vụ process có thể được khởi tạo trên nhiều CPU khác nhau. Khi đó chúng ta sẽ có Xử lý song song (Parallel). Mô tả khác nhau cơ bản giữa Concurrency và Parallel các bạn có thể tham khảo hình dưới đây: Vấn đề với process là việc khởi tạo, switching context giữa các process là tương đối tốn tài nguyên (Vì các process là độc lập). Đối với PHP, chúng ta có PHP-FPM và process pool để phần nào giảm tải việc này, tuy nhiên, vẫn có những cách tối ưu hơn để giải quyết vấn đề process. MultithreadingCác thread cũng được khởi tạo và quản lý lập lịch bởi OS. Tuy nhiên, khác với process, các thread trên cùng process sẽ dùng chung một không gian bộ nhớ. Vấn đề với thread là việc sử dụng chung tài nguyên có thể dẫn đến những tranh chấp nếu chúng ta bất cẩn. Khởi tạo nhiều thread trên nhiều process, switching context giữa các thread cũng tương đối tốn kém tài nguyên. CoroutineCoroutine là kết hợp giữa co-operate và routine. Ở đây các tác vụ sẽ được coi là routine, và được chạy Concurrency. Coroutine cũng giống như thread, khi các routine có thể chia sẻ chung tài nguyên, và có cơ chế giao tiếp với nhau. Ví dụ ở đầu của chúng ta sẽ có một chút thay đổi
Các bạn sẽ thấy có những đoạn yield. Đó chính là lúc runtime (hoặc developer) đánh dấu việc có thể nhường lại quyền chuyển đổi giữa các routine để tiếp tục khởi chạy các routine khác. Chúng ta có thể diễn giải
Đối với cá nhân mình, coroutine có nét khá giống với callback handler trên JS. Ở đây việc lập lịch, đã không còn nằm trong tay OS nữa mà là runtime. Điều này dẫn chúng ta đến một khái niệm khá phổ biến: Non-blocking I/O. Các tác vụ I/O xuất hiện rất nhiều trong các ứng dụng: Khởi tạo kết nối database, gửi HTTP Request … Về cơ bản, những tác vụ chúng ta gửi đầu vào (Input) và chờ đợi đầu ra (Output) đều có thể gọi là tác vụ I/O. Việc sử dụng Coroutine sẽ yêu cầu các thư viện, các đoạn code hỗ trợ Non-blocking (cơ chế trả quyền switch context cho runtime), nếu không chúng ta sẽ ko có Concurrency và quay về với việc chạy đồng bộ truyền thống. Lợi thế lớn của coroutine đó là việc được quản lý bởi runtime, nên chi phí tài nguyên tốn rất ít. Một coroutine chỉ tốn khoảng 2KB để khởi tạo (Thread có thể được phân phối từ 1 đến vài MB khác nhau). Chúng ta cũng có thể khởi tạo hàng nghìn coroutine trên một thread, giúp ứng dụng của chúng ta có hiệu suất cao. Vấn đề với coroutine là việc share chung tài nguyên cũng cần tốn thêm quản lý khi lập trình. Việc yield giữa các routine cũng cần cẩn trọng để tránh có những kết quả không mong muốn. Đối với PHP, nếu muốn chuyển sang coroutine, ví dụ Swoole, chi phí chuyển đổi cũng lớn vì sẽ phải thay thế các thư viện sang non-blocking IO. Bất đồng bộ PHPPHP đã từ bỏ khái niệm thread. Chúng ta sẽ dựa hoàn toàn vào Process để triển khai Concurrency. Bên cạnh thread, coroutine PHP cũng phát triển với rất nhiều thư viện hỗ trợ như Swoole, amp, roadrunner. Gần đây nhất, trong phiên bản PHP 8.1, PHP đã chính thức hỗ trợ Coroutine dưới tên Fiber (Trước đây, để làm Coroutine với PHP thuần túy thường phải tận dụng Generators, khá khó kiểm soát). PHP mô tả Fiber như là một kỹ thuật cấp thấp để quản lý các các tác vụ song song. Một ví dụ về Fiber trong PHP như sau:
Như các bạn thấy, chúng ta có thể dễ dàng suspend và resume một Fiber thông qua các API mà PHP cung cấp. Điều này sẽ là một lợi thế rất lớn, mở ra những cách khai thác mới lạ cho PHP như xây dựng Eventloop, xử lý WebSocket trên PHP. Techmaster sẽ sớm bổ sung các bài viết chuyên sâu về kỹ thuật này trên PHP. Cám ơn các bạn đã theo dõi bài viết, hy vọng nó đã cung cấp cho các bạn nhiều góc nhìn về xử lý song song trên PHP. Khóa học PHP Fullstack - Khóa học dành người mới bắt đầu, kiến thức dễ tiếp cận, lộ trình vừa sức, dễ xin việc, tạo nền móng cho sự nghiệp theo đuổi con đường lập trình.
|