2012-02-03 27 views
6

Tôi đang tìm một phương pháp chung để khởi động và sau đó giết một quá trình R, bao gồm cả tất cả các nhánh hoặc các quy trình khác mà nó viện dẫn.đệ quy giết R quá trình với trẻ em trong linux

Ví dụ, một người dùng chạy một kịch bản như thế này:

library(multicore); 
for(i in 1:3) parallel(foo <- "bar"); 
for(i in 1:3) system("sleep 300", wait=FALSE); 
for(i in 1:3) system("sleep 300&"); 
q("no") 

Sau khi người dùng bỏ phiên R, các quá trình con vẫn đang chạy:

[email protected]:~$ ps -ef | grep R 
jeroen 4469  1 0 16:38 pts/1 00:00:00 /usr/lib/R/bin/exec/R 
jeroen 4470  1 0 16:38 pts/1 00:00:00 /usr/lib/R/bin/exec/R 
jeroen 4471  1 0 16:38 pts/1 00:00:00 /usr/lib/R/bin/exec/R 
jeroen 4502 4195 0 16:39 pts/1 00:00:00 grep --color=auto R 
[email protected]:~$ ps -ef | grep "sleep" 
jeroen 4473  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4475  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4477  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4479  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4481  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4483  1 0 16:38 pts/1 00:00:00 sleep 300 
jeroen 4504 4195 0 16:39 pts/1 00:00:00 grep --color=auto sleep 

Để làm cho mọi việc tồi tệ hơn, họ id quá trình cha mẹ của chúng là 1 khiến việc xác định chúng trở nên khó khăn. Có một phương pháp để chạy một kịch bản R theo cách cho phép tôi đệ quy giết chết quá trình và các con của nó bất cứ lúc nào?

Chỉnh sửa: vì vậy, tôi không muốn phải theo cách thủ công để tìm kiếm các quy trình xóa & theo cách thủ công. Ngoài ra tôi không muốn giết tất cả các quy trình R, vì có thể có những người khác đang làm tốt. Tôi cần một phương pháp để giết một quá trình cụ thể và tất cả các con của nó.

+0

Chỉ cần không giết PID 1 - nó sẽ * không * làm những gì bạn muốn. Vâng, thực sự nó sẽ ... loại ... – thkala

+0

lol @thkala oh có nó sẽ làm nhiều hơn anh ta mặc cả cho :) và tại sao không chỉ đơn giản là loại bỏ nhị phân này? –

Trả lời

8

này chủ yếu là về đa lõi phần. Trẻ em đang chờ bạn thu thập kết quả - xem ?collect. Thông thường, bạn không bao giờ nên sử dụng parallel mà không có một điều khoản để làm sạch, thường là trong on.exit. đa lõi làm sạch các chức năng cấp cao như mclapply, nhưng nếu bạn sử dụng chức năng cấp thấp hơn, bạn có trách nhiệm thực hiện dọn dẹp (vì đa lõi không thể biết liệu bạn có để trẻ em cố tình chạy hay không).

Ví dụ của bạn thực sự không có thật, bởi vì bạn thậm chí không cân nhắc việc thu thập kết quả. Nhưng dù sao, nếu đó thực sự là những gì bạn muốn, bạn sẽ phải làm việc dọn dẹp tại một số điểm. Ví dụ, nếu bạn muốn chấm dứt tất cả trẻ em trên lối ra, bạn có thể xác định .Last như thế này:

.Last <- function(...) { 
    collect(wait=FALSE) 
    all <- children() 
    if (length(all)) { 
     kill(all, SIGTERM) 
     collect(all) 
    } 
} 

Một lần nữa, phía trên là không một cách khuyến khích để đối phó với điều này - nó chứ không phải là một phương sách cuối cùng. Bạn thực sự nên phân công công việc và thu thập kết quả như

jobs <- lapply(1:3, function(i) parallel({Sys.sleep(i); i})) 
collect(jobs) 

Đối với các câu hỏi quá trình con chung - init thừa hưởng những đứa trẻ chỉ sau R bỏ, nhưng trong .Last bạn vẫn có thể tìm PID của họ kể từ khi quá trình cha mẹ tồn tại vào thời điểm đó để bạn có thể thực hiện dọn dẹp tương tự như trong trường hợp đa lõi khác.

+0

Cảm ơn. Vấn đề là đôi khi người dùng (tôi giả sử vô tình) để lại một mớ hỗn độn trên các máy chủ của tôi. Tôi đang cố gắng để sandbox nó xuống bằng cách hạn chế quyền và làm sạch sau khi họ bất cứ nơi nào có thể. – Jeroen

+0

+1 Đây là lời khuyên hữu ích và giúp mở rộng tài liệu một cách hữu ích. Không phải là tài liệu cho 'đa lõi' là xấu, tác giả thân yêu của' đa lõi', nhưng làm chủ 'fork' và' collect' được làm dễ dàng hơn với nhiều ví dụ và lời khuyên hơn. – Iterator

+0

@Jeroen Đủ công bằng. Thật không may làm sạch trong R là tự nguyện. Tuy nhiên, bạn có thể viết một hàm C nhỏ và đăng ký nó với 'atexit' để bắt buộc dọn dẹp trong mọi trường hợp (ngoại trừ các sự cố - chỉ các trình xử lý tín hiệu mới có thể trợ giúp). –

4

Trước khi người dùng thoát phiên R, các quy trình bạn muốn giết sẽ có ID tiến trình cha bằng ID tiến trình của phiên bắt đầu chúng. Bạn có thể sử dụng các móc .Last hoặc .Last.sys (xem help(q)) để tiêu diệt tất cả các quy trình với PPID phù hợp tại thời điểm đó; những người có thể bị đàn áp với q(runLast=FALSE), vì vậy nó không phải là hoàn hảo, nhưng tôi nghĩ rằng đó là lựa chọn tốt nhất mà bạn có.

Sau người dùng bỏ phiên R, không có cách nào đáng tin cậy để làm những gì bạn muốn - kỷ lục chỉ kernel giữ của quá trình tư cách bà con là PPID bạn thấy trong ps -ef, và khi một quá trình cha mẹ thoát, thông tin đó bị phá hủy, như bạn đã khám phá ra.

Lưu ý rằng nếu một trong những đứa trẻ quá trình dĩa, các cháu sẽ có PPID bằng với con 's PID, và điều đó sẽ được thiết lập lại để 1 khi con lối thoát hiểm, mà nó có thể làm trước khi ông bà ra đi. Do đó, không có cách nào đáng tin cậy để bắt được tất cả của con cháu của quá trình nói chung, ngay cả khi bạn làm như vậy trước khi quá trình thoát. (Một nghe rằng "cgroups" cung cấp một cách, nhưng một là không quen thuộc với các chi tiết; trong mọi trường hợp, đó là một tính năng tùy chọn mà chỉ có một số lần lặp lại/cấu hình của hạt nhân Linux cung cấp, và không có sẵn ở tất cả mọi nơi.)

+1

Bạn cũng có thể muốn xem 'ps aux --forest', cung cấp thông tin giống như PPID (nó phải được thực hiện trước khi cha mẹ chết), đồ họa hơn. Nó rất hữu ích nếu bạn có nhiều thế hệ các quy trình. –

+1

Thật không may, ngay cả trước khi quá trình cha mẹ chết, trẻ em đã được bắt đầu với hệ thống() lệnh sẽ có id mẹ 1. – Jeroen

+0

@Jeroen Không nhất thiết: ví dụ 'hệ thống (" ngủ 300 ")' sẽ không, nhưng ' hệ thống ("ngủ 300 &") 'sẽ. Tuy nhiên, tùy thuộc vào mức độ phức tạp của lệnh và chính xác mà hệ điều hành, thư viện C và '/ bin/sh' bạn có, có thể có quá trình' sh' trung gian treo xung quanh và gây nhầm lẫn cho vấn đề. – zwol

1

Tôi tin rằng phần sau của câu hỏi là xem xét nhiều hơn về trình bao, chứ không phải hạt nhân. (Simon Urbanek đã trả lời phần multicore tốt hơn so với khá nhiều bất cứ ai khác có thể, khi ông là tác giả. :))

Nếu bạn đang sử dụng bash, bạn có thể tìm PID của tiến trình con vừa ra mắt nhất trong $!. Bạn có thể tổng hợp các PID và sau đó chắc chắn để diệt chúng khi bạn đóng R.

Nếu bạn muốn thực sự gonzo, bạn có thể lưu trữ PID mẹ (tức là đầu ra của Sys.getpid()) và PID con trong một tệp và một daemon làm sạch để kiểm tra xem liệu có tồn tại hay không, và nếu không, sẽ giết chết các trẻ mồ côi. Tuy nhiên, tôi không nghĩ rằng sẽ dễ dàng nhận được một gói có tên là oRphanKilleR vào CRAN.

Dưới đây là một ví dụ về phụ trẻ PID vào một tệp:

system('(sleep 20) & echo $! >> ~/childPIDs.txt', wait = FALSE) 

Bạn có thể sửa đổi này để tạo lệnh shell của riêng bạn và sử dụng lệnh R của tempfile() để tạo ra một tập tin tạm thời (mặc dù, đó sẽ biến mất khi cá thể R bị chấm dứt, trừ khi bạn thực hiện một nỗ lực đặc biệt để bảo vệ tệp thông qua các quyền).

Đối với một số ý tưởng thông minh khác, hãy xem this other post on SO.

Bạn cũng có thể tạo vòng lặp do while trong trình bao sẽ kiểm tra xem có tồn tại một PID cụ thể hay không. Trong khi đó, vòng lặp ngủ. Khi vòng lặp kết thúc (vì PID không còn được sử dụng nữa), tập lệnh sẽ giết một PID khác.

Về cơ bản, tôi nghĩ rằng giải pháp của bạn sẽ nằm trong kịch bản vỏ, chứ không phải là R.

Các vấn đề liên quan