Giao tiếp giữa các quá trình python

Xin chào các bạn. Hôm nay mình sẽ giới thiệu vs các bạn một kỹ thuật, khái niệm hơi cao cấp trong lập trình, mang tên là "lập trình đa tiến trình", tiếng anh gọi là "lập trình đa tiến trình"

Nếu bạn đã từng nghe và sử dụng kỹ thuật này thì không sao cả, bài này sẽ giúp bạn hiểu rõ hơn và biết thêm 1 số thứ. Còn nếu chưa từng nghe và tìm hiểu thì đây sẽ là một kỹ thuật khá mới và bổ ích, được sử dụng khá nhiều trong các bài toán, hệ thống lớn.  

2. Khái niệm process and thread

Trước hết chúng ta cần hiểu hai khái niệm "tiến trình" và "luồng"

Đại xác thực, tiến trình [tiến trình] có thể hiện của mỗi chương trình/ứng dụng độc lập đang chạy trên hệ thống/hệ điều hành [không chạy thì ko gọi là tiến trình nhé]. Mỗi tiến trình sẽ không có không gian, vùng nhớ, tập hợp các câu lệnh [chỉ dẫn] để chạy tiến trình đó. Mỗi một tiến trình cũng sẽ có 1 cái định danh là process id, hệ điều hành sẽ sử dụng process id để quản lý tiến trình. Ứng dụng, hệ thống hay một dịch vụ nào đó mà bạn đang sử dụng có thể là kết hợp của nhiều tiến trình [hoặc chỉ là 1 tiến trình]

Trên cửa sổ, để hiển thị danh sách các quy trình, bạn vào trình quản lý tác vụ có tính năng. Trên Linux, để hiển thị danh sách các tiến trình đang chạy, bạn sử dụng câu lệnh ps như hình bên dưới. Cụ thể về câu lệnh này và các thông tin liên quan, bạn có thể tìm hiểu kỹ hơn câu lệnh trên google

Mỗi một tiến trình mà bạn chạy, có thể có nhiều luồng [thread]. Các bài hát hoạt động của luồng trong cùng một tiến trình để thực hiện các nhiệm vụ bất kỳ của tiến trình

Hiểu nôm na thì máy tính bạn chạy như hiện tại có nhiều tiến trình, mỗi tiến trình có nhiều luồng cùng chạy, hay có thể nói luồng [luồng] là một phần [hoặc là con] của một tiến trình [tiến trình]

3. Sự khác nhau giữa process và thread

Bàn về luồng và chủ đề, có rất nhiều bài viết. Các bạn có thể tham khảo tại link sau

https. // vivadifferences. com/13-sự-khác-biệt-giữa-tiến-trình-và-luồng-trong-os/

https. //www. gu99. com/sự khác biệt giữa quá trình và luồng. html

https. //www. chuyên viên máy tính. org/sự khác biệt giữa quá trình và luồng/

Tuy nhiên, để rút gọn và dễ nhớ, mình viết một vài ý chính có thể hiện sự khác nhau của 2 cái này như sau

ProcessThreadMột bản có thể độc lậpLà một phần, là con của tiến trình Sử dụng vùng nhớ độc lậpSử dụng vùng nhớ chung với tiến trình cha, có thể chia sẻ vùng nhớ với các luồng có chung tiến trìnhKhi tiến trình chết [có thể bị buộc bởi tác nhân khác]

Với bảng so sánh trên, hãy chú ý vào phần tô đậm. Đó vừa là ưu điểm, vừa là nhược điểm lớn nhất của 2 khái niệm này. Tùy mục đích của bài toán, tính năng, bạn nên chọn lập trình đa tiến trình hay đa luồng, không có cái gì là chắc chắn có lợi thế

4. Bài toán lập trình đa tiến trình, ưu và nhược

Khi lập trình và phát triển các sản phẩm, nhiều lúc chương trình của bạn cần "thực hiện nhiều nhiệm vụ cùng một lúc". It could be

  • Xử lý nhiều nhiệm vụ giống nhau ở cùng thời điểm
  • Xử lý các nhiệm vụ khác nhau theo một cách đồng thời [ví dụ: một nhiệm vụ luôn đọc dữ liệu, một nhiệm vụ luôn ghi dữ liệu]

Lúc này bạn cần chọn giải pháp "lập trình đa luồng" hay "lập trình đa tiến trình". Mình ví dụ với một bài toán cụ thể mà mình đã từng làm cách đây 3 năm như sau

"Ứng dụng Việt chỉnh sửa ảnh của người dùng, theo đó mỗi người dùng gửi lên một ảnh thì bạn sẽ xử lý và gửi trả lại người dùng một ảnh đã xử lý"

Với bài toán như trên, bạn tưởng tượng rằng mình cần có nhiều luồng/tiến trình, trong đó mỗi luồng/tiến trình [gọi là 1 công nhân] chắc chắn sẽ nhận được 1 trong các công việc như sau

  • Loại nhiệm vụ 1. N công nhân lắng nghe/ghi nhận ảnh gửi lên của người dùng [mỗi khi 1 người dùng gửi lên ta cần 1 công nhân lắng nghe và ghi nhận]
  • Loại nhiệm vụ 2. M công nhân để xử lý ảnh của người dùng tại 1 thời điểm
  • Loại nhiệm vụ 3. K công nhân để gửi ảnh đã chỉnh sửa trả về cho người dùng

Như vậy có thể thấy một bài toán như thế này, bạn đã phải sử dụng rất nhiều luồng/tiến trình để giải quyết. Việc sử dụng nhiều luồng/tiến trình không chắc chắn giúp bạn tăng tốc độ xử lý [tham khảo bài viết này], nhưng chắc chắn dễ tổ chức và dễ cài đặt hơn [chuyên môn hóa từng nhiệm vụ]

Với bài toán của mình, lúc đầu mình xử lý tất cả bằng cách thiết lập trình đa luồng [chi phí cpu và ram tạo ra nhiều luồng tốt hơn nhiều tiến trình]. Và rồi 1 ngày mình phát hiện ra, vs loại nhiệm vụ số 2 [xử lý ảnh], thì tỷ lệ sập chương trình lên tới 20%. Và lúc này các yếu tố điểm của việc lập trình đa luồng được lộ ra, đó là chỉ cần 1 luồng bị treo thì cả tiến trình [tiến trình] sẽ tiếp tục hoạt động theo. Trong khi đó, nếu lập trình đa tiến trình, một con tiến trình bị chết thì tiến trình chính vẫn hoạt động bình thường, bạn có thể cài đặt lý do ngoại lệ/báo lỗi trong quá trình xử lý trong tiến trình chính [tổng thể hoạt động

Nếu bạn lập trình C++ nhiều, bạn sẽ thấy tỷ lệ đoạn mã bị crash khá cao [các vđ liên quan tới con trỏ, bộ nhớ]. Và nếu chương trình của bạn thiết lập chương trình đa luồng và 1 luồng nào sử dụng đoạn mã có tỷ lệ sự cố cao như thế, thì hậu quả là cả chương trình sẽ thường xuyên bị sự cố. Ý tưởng cải tiến ở đây là, chúng ta tạo ra 1 process chính có nhiệm vụ quản lý các process con, các process con mà bị chết thì process chính vẫn ko sao, có thể tạo lại process con chạy lại từ đầu

Hình dưới minh họa điểm mạnh trong việc kiểm tra sự cố giữa ứng dụng đa tiến trình và một tiến trình đa luồng

Có 1 sự thật là, khoảng 60% các sản phẩm mình code trên hệ điều hành Linux bằng ngôn ngữ C++ đc code theo kiến ​​trúc đa tiến trình. Lí do thì khá đơn giản, đó là do mình hay sử dụng các mã nguồn mở có ẩn chứa tỷ lệ crash khá cao. Lập trình đa tiến trình theo mình tác dụng lớn nhất là như thế nào [kiểm soát tốt hơn sự cố]

À còn 1 điểm quan trọng nữa đó là, nếu lập trình đa luồng thì bạn cần viết mã tất cả bằng một ngôn ngữ [ví dụ như C++ hay C#], nhưng nếu lập trình đa luồng, bạn có thể tùy chọn từng nhiệm vụ . Ví dụ và bài toán của mình, nhiệm vụ 1 và 3 các bạn dùng C# [hay Python hoặc Java], còn nhiệm vụ 2 các bạn dùng C++, rất tiện lợi phải không?

Tuy nhiên, nhược điểm của việc lập trình đa tiến trình là thời gian khởi động một tiến trình rất lâu và bộ nhớ CPU hơi hư hỏng. Để truyền tham số, giao tiếp liên lạc giữa các tiến trình vs nhau cũng là 1 bài toán khó khăn khác mà người lập trình phải giải quyết. Do đó, mình gọi kỹ năng lập trình đa tiến trình là kỹ năng hơi cao cấp

Chốt lại, nếu chương trình bạn viết ổn định [không crash], được phát triển bởi cùng một ngôn ngữ, thì bạn có thể sử dụng đa luồng để đạt hiệu suất cao và cài đặt dễ dàng. Ngược lại, nếu chương trình hay gặp sự cố và được phát triển bởi nhiều ngôn ngữ lập trình, bạn nên nghĩ đến hướng thiết lập đa tiến trình

Lập trình đa tiến trình cũng không phải chỉ được áp dụng cho các ứng dụng máy tính để bàn đâu nhé. Khá nhiều ứng dụng điện thoại cũng đc phát triển theo hình thức này, khi vỏ bọc/giao diện đc code bằng Java, còn core function đc code bằng C++ và chạy ở 1 web split process. Với ứng dụng web chính CodeLearn. io mà các bạn đang dùng thì cũng có 1 đoạn nhỏ đoạn mã phía server đc code theo thiết kế đa tiến trình nha

5. Lập trình đa tiến trình như thế nào?

Lập trình đa tiến trình là về cơ bản, bạn sẽ có 1 tiến trình chính [main process], sau đó tiến trình này sẽ đẻ ra các tiến trình con để làm việc. Nhiệm vụ của tiến trình chính khá đơn giản, không thể có lỗi, thường là nhiệm vụ quản lý và giao việc cho các tiến trình con hơn là trực tiếp xử lý một công việc gì đó

Rút gọn lại

  • Create main process, main process call the process con
  • Tiến trình nhận nhiệm vụ [thường là nhận nhiệm vụ thông qua giao tiếp so với tiến trình chính], xử lý công việc liên tục
  • Tiến trình chính quản lý tiến trình con, nếu thằng con chết/treo/hoàn thành nhiệm vụ thì xử lý [xác thì tạo mới, treo thì dừng,. ]

Để thiết lập chương trình được, bạn cần biết các kỹ thuật chính như

  • Main processtạo ra con process như thế nào?
  • Process conNhận tham số, công việc từ main process ra sao?
  • Làm sao để tiến trình chính biết chương trình con hoạt động ntn [còn sống hay đã chết, có bị treo hay không,. ]

Chú ý rằng mỗi tiến trình sẽ là một chương trình/không gian chạy độc lập. Do đó, nếu lập trình đa tiến trình, bạn sẽ có nhiều hàm chính. Một hàm chính có thể hiện tiến trình chính, một vài hàm chính có thể hiện tiến trình phụ. Tất cả các đoạn mã cần được xây dựng thành công và có thể chạy độc lập vs nhau

6. Create and run process con

Để chạy một tiến trình con khá đơn giản, với C# bạn sử dụng Hệ thống lớp. chẩn đoán. tiến trình

Chung với các ngôn ngữ để chạy một tiến trình bạn cần

  • Đường dẫn của chương trình mà bạn cần chạy [ví dụ
    System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
    while [!process.HasExited]
    {
        //update UI
    }
    0]
  • Các tham số truyền vào chương trình đó
  • Các tùy chọn khác nhau [tùy chọn từng ngôn ngữ]

Với C++, để chạy một trình đơn đơn giản nhất có thể, bạn có thể sử dụng câu lệnh System vs cú pháp

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
1

Riêng với ngôn ngữ C++ trên hđh Linux, C++ cung cấp 1 hàm để tạo ra process con một cách khá đặc biệt mà bạn không thể tìm thấy ở các ngôn ngữ khác là hàm

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
2. Trong giới hạn của bài viết này không đủ thời gian để giải thích chi tiết hơn, mình nên gửi cho các bạn link tham khảo dưới đây [hẹn bài khác nha]

http. //www. yolinux. com/HƯỚNG DẪN/ForkExecProcesses. html

Có 1 chú ý rất lớn, đó là nếu bạn chạy một tiến trình thông thường, bạn sẽ không nắm bắt được trạng thái kết thúc hoặc một số bộ phận của tiến trình mà bạn vừa chạy. Trong phần lớn thiết lập trình đa tiến trình, bạn cần nắm giữ trạng thái của tiến trình con sau khi được chạy để đưa ra các xử lý phù hợp. Please read next to the bottom of the nha

7. Truyền tham số cho tiến trình con

Một bài toán khá quan trọng trong lập trình đa tiến trình, đó là truyền tham số cho chương trình con

Lấy ví dụ bài toán xử lý ảnh trong ví dụ của mình, đó là giả sử mỗi tiến trình con cần xử lý một cái ảnh mà người dùng gửi lên. Khi đó, tiến trình chính cần gửi tham số là cái ảnh đó cho các chương trình con xử lý, và chương trình con cần trả lại kết quả đã xử lý cho chương trình cha

Cách truyền tham số cho chương trình con đơn giản nhất, chính là cách truyền tham số theo dạng dòng lệnh

  • Con process con process argc tham số nhận vào từ dòng lệnh [thông qua tham số argc, argv trong hàm main]
  • Tham số truyền tham số cho chương trình con khi khởi động

Đến phần này, đương nhiên bạn đã hiểu 2 tham số argc và argv trong hàm main của mỗi chương trình mà bạn viết để làm gì chưa?

Đối với phần lớn các ngôn ngữ lập trình, hàm chính nào cũng có 2 tham số

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
3 và
System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
4. Argc là một số nguyên có thể hiện các tham số truyền vào trong tiến trình của bạn,
System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
4 là một mảng bao gồm
System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
3 các xâu ký tự có thể hiển thị các tham số truyền vào

Ví dụ như nếu bạn nhập

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
0 thì ping chính là tên tiến trình của bạn,
System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
1,
System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
2

Để tìm hiểu thêm, hãy thử tìm kiếm theo từ khóa

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
3 kèm theo ngôn ngữ mà bạn mong muốn nhé. Hẹn 1 hôm nào rảnh, mình sẽ viết chi tiết 1 bài về kỹ thuật này sau

Rồi, bây giờ giả sử tiến trình con của bạn đã xử lý các tham số từ dòng lệnh, vậy thì truyền tham số khi chạy từ tiến trình cha ra sao? . Tham khảo C# dòng lệnh như sau

ProcessStartInfo startInfo = new ProcessStartInfo["IExplore.exe"];
startInfo.WindowStyle = ProcessWindowStyle.Minimized;

Process.Start[startInfo];

// set command line arguments for process
startInfo.Arguments = "www.northwindtraders.com";

8. Giao tiếp giữa 2 tiến trình - IPC?

Với đơn giản bài toán, tiến trình cha gọi tiến trình con rồi tiến trình con cứ thế chạy là xong. Nhưng có nhưng bài toán rất phức tạp, bạn cần tiến trình con giao tiếp liên tục với tiến trình cha, thì làm thế nào???

Để giao tiếp giữa các tiến trình cha và con, hay giữa các tiến trình độc lập với nhau, người ta sử dụng thuật ngữ/kĩ thuật gọi là liên tiến trình-giao tiếp-ipc

Lấy ví dụ tiến trình con cần xử lý 1 công việc trong thời gian rất dài và liên tục phải thông báo cho tiến trình cha về số % công việc đã làm đc thì bạn sẽ xử lý ntn? . Nhưng giữa các quá trình thì không có chuyện đó, kỹ thuật trao đổi dữ liệu trở nên khó khăn hơn rất nhiều

Ở phạm vi bài viết này, mình sẽ chỉ nói sơ thôi. Cái này cũng đành hẹn có 1 bài viết chuyên sâu hơn về IPC cùng những điểm ưu việt của các phương pháp. Ở đây nói ngắn gọn, sẽ có nhiều kỹ thuật chính

  • Use stdin/stdout. you write output of process A ra stdout of A, process B read stdout of A rồi xử lý. Hoặc bạn ghi dữ liệu vào stdin của tiến trình A từ tiến trình B
  • used file. ghi và nhận dữ liệu qua một tệp trung gian
  • Sử dụng socket/pipe. một cách thức truyền nhận dữ liệu thông qua các ống và ổ cắm, như kiểu lắp đường ống nước để xoay chuyển nước giữa các công trình nhà nó
  • Use database

Chi tiết về các kỹ thuật này các bạn có thể search vs từ khóa tương ứng hoặc đọc thêm bài mà mình đã gửi link ở trên nha

9. Trình quản lý được tạo ra

Một bài toán quan trọng trong thiết lập đa tiến trình, chính là quản lý tiến trình được tạo ra như

  • Tiến trình đã hoàn thành bình thường, làm sao để biết
  • Tiến trình chạy quá lâu, cần tiêu diệt/dừng hoạt động
  • Lỗi process process, sao biết lỗi?

To accept the process has been complete, has 1 number as after

  • Lưu id của process con, sau đó dùng lệnh kiểm tra process đó còn chạy hay không?
  • trước khi quá trình kết thúc con, hãy báo hiệu cho tiến trình cha rằng quá trình con đã kết thúc [thông qua các phương pháp như mục 8]
  • Đối với 1 số ngôn ngữ [không phải là tất cả], có 1 cách để đăng ký lời gọi khi quá trình kết thúc. Cái này bạn tra google xem

Với phần lớn các ngôn ngữ, phương án số 1 hoặc được áp dụng và hỗ trợ. Vui lòng xem thử thông qua ví dụ bằng ngôn ngữ C# như sau

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}

Trường hợp process chạy quá lâu, bạn có thể dừng process đó. Bạn có thể giới hạn thời gian chạy của tiến trình thông qua api

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
4 hoặc đo thời gian chạy của chương trình xem nó có kết thúc trong khoảng thời gian cho phép hay không?

Trường hợp bạn muốn dừng chương trình một cách đột ngột, hãy sử dụng api

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
5

Với C++ hay C# [Java không rõ có ko] có lệnh rất mạnh [cần chạy bằng quyền admin/root] để tiêu diệt/dừng tiến trình nào đang chạy, đó là lệnh

System.Diagnostics.Process process = System.Diagnostics.Process.Start["cmd.exe"];
while [!process.HasExited]
{
    //update UI
}
6 Để sử dụng lệnh này, bạn cần . Chú ý nếu bạn tắt 1 process hệ thống, máy tính của bạn có thể khởi động lại ngay lập tức nhé

Trong khi thiết lập trình đa luồng, bạn có thể sử dụng try catch để bắt các lỗi/lệch còn thiết lập trình đa tiến trình thì không. Hãy cố gắng để tiến trình không có lỗi, nếu có lỗi, bạn có thể bắt lỗi trong chính tiến trình bị lỗi, ghi các lỗi này ra tệp/cơ sở dữ liệu hoặc thiết bị xuất chuẩn trước khi thoát để xử lý sau

10. Tổng kết

Một bài viết khá dài nhưng cũng chưa chắc đầy đủ về lập trình đa tiến trình. Mình sẽ dành thêm thời gian để viết những bài và kỹ thuật liên quan

Mong rằng bài viết giúp các bạn hiểu biết thêm và vận dụng 1 số kiến ​​thức vào sản phẩm của các bạn

Chủ Đề