2013-08-03 31 views
13

Tôi đang cố gắng chạy vòng lặp foreach trên máy chủ Windows với CPU lõi 16 và 64 GB RAM bằng RStudio. (sử dụng gói doParallel)đọc các biến toàn cầu bằng cách sử dụng foreach trong R

Quy trình "công nhân" sao chép tất cả các biến từ bên ngoài vòng lặp (được quan sát bằng cách xem sự khởi tạo của các quy trình này trong trình quản lý tác vụ cửa sổ khi vòng lặp foreach được chạy), do đó làm đầy lên bộ nhớ được sử dụng bởi mỗi quá trình. Tôi đã cố gắng khai báo một số biến đặc biệt lớn như toàn cục, đồng thời đảm bảo rằng các biến này cũng được đọc từ và không được ghi vào bên trong vòng lặp foreach để tránh xung đột. Tuy nhiên, các quy trình vẫn nhanh chóng sử dụng hết bộ nhớ có sẵn.

Có cơ chế để đảm bảo rằng quy trình "công nhân" không tạo bản sao của một số biến "chỉ đọc" không? Chẳng hạn như một cách cụ thể để khai báo các biến như vậy?

+0

Tôi về cơ bản đã hỏi cùng một câu hỏi trong một thời gian trước (http://stackoverflow.com/questions/6251662/writing-to-global-environment-when-running-in-parallel), nhưng mọi thứ có thể đã thay đổi ở mức trung bình thời gian? –

+0

Cảm ơn Roman, tôi cũng bị mắc kẹt trên Windows; hy vọng ai đó biết cách thoát ra ngoài. Tôi không cần bình chọn/thay đổi biến lớn (mạng) vì tôi chỉ đọc nó để tính toán điểm số trung tâm .. – user2272413

+1

Tùy thuộc vào dữ liệu bạn muốn chia sẻ có thể được biểu diễn bằng ma trận hay không, gói 'bigmemory' có thể cho phép những gì bạn đang theo dõi. Gói đó cho phép truy cập chia sẻ để xử lý song song, ngay cả trên các cửa sổ. Tuy nhiên, nếu đối tượng chia sẻ không thể được biểu diễn bằng ma trận, bạn sẽ không đi xa trên con đường đó. – BenBarnes

Trả lời

14

Gói doParallel sẽ tự động xuất biến cho công nhân được tham chiếu trong vòng foreach. Nếu bạn không muốn làm điều đó, bạn có thể sử dụng tùy chọn foreach ".không xuất hiện" để ngăn không cho tự động xuất các biến cụ thể. Nhưng nếu tôi hiểu bạn một cách chính xác, vấn đề của bạn là R sau đó nhân bản một số biến đó, mà thậm chí còn nhiều vấn đề hơn bình thường vì nó đang xảy ra trong nhiều tiến trình trên một máy.

Không có cách nào để khai báo biến để R sẽ không bao giờ sao chép biến đó. Bạn cần phải thay thế các biến vấn đề với các đối tượng từ một gói như bigmemory sao cho các bản sao không bao giờ được thực hiện hoặc bạn có thể thử sửa đổi mã theo cách sao cho không kích hoạt tính năng sao chép. Bạn có thể sử dụng chức năng tracemem để giúp bạn, vì nó sẽ in một tin nhắn bất cứ khi nào đối tượng đó được nhân bản.

Tuy nhiên, bạn có thể tránh được sự cố bằng cách giảm dữ liệu cần thiết cho công nhân. Điều đó làm giảm lượng dữ liệu cần phải được sao chép vào từng công nhân, cũng như giảm lượng bộ nhớ của chúng.

Dưới đây là một ví dụ điển hình của việc cho người lao động dữ liệu hơn là họ cần:

x <- matrix(1:100, 10) 
foreach(i=1:10, .combine='c') %dopar% { 
    mean(x[,i]) 
} 

Kể từ khi ma trận x được tham chiếu trong foreach vòng lặp, nó sẽ được tự động xuất khẩu cho mỗi người lao động, thậm chí mặc dù mỗi công nhân chỉ cần một tập con của các cột. Giải pháp đơn giản nhất là để lặp qua các cột thực tế của ma trận chứ không phải qua các chỉ số cột:

foreach(xc=x, .combine='c') %dopar% { 
    mean(xc) 
} 

Không chỉ là ít dữ liệu chuyển giao cho người lao động, nhưng mỗi công nhân chỉ thực sự cần phải có một cột trong bộ nhớ tại một thời điểm, làm giảm đáng kể dung lượng bộ nhớ của nó đối với các ma trận lớn. Các vector xc vẫn có thể kết thúc được nhân đôi, nhưng nó không làm tổn thương gần như nhiều vì nó là nhỏ hơn nhiều so với x. Lưu ý rằng kỹ thuật này chỉ giúp khi doParallel sử dụng các chức năng "có nguồn gốc từ tuyết", chẳng hạn như parLapplyclusterApplyLB, chứ không phải khi sử dụng mclapply. Sử dụng kỹ thuật này có thể làm cho vòng lặp chậm hơn một chút khi sử dụng mclapply vì tất cả các nhân viên đều nhận được ma trận x miễn phí, vậy tại sao lại chuyển xung quanh các cột khi công nhân đã có toàn bộ ma trận? Tuy nhiên, trên Windows, doParallel không thể sử dụng mclapply, vì vậy kỹ thuật này rất quan trọng.

Điều quan trọng là phải suy nghĩ về những dữ liệu thực sự cần thiết cho công nhân để thực hiện công việc của họ và cố gắng giảm nó nếu có thể. Đôi khi bạn có thể làm điều đó bằng cách sử dụng các trình vòng lặp đặc biệt, hoặc từ các gói iterators hoặc itertools, nhưng bạn cũng có thể thực hiện điều đó bằng cách thay đổi thuật toán của mình.

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