2014-07-18 22 views
5

Tôi đang cố gắng xử lý> 10000 xts đối tượng được lưu trên đĩa mỗi khoảng 0,2 GB khi được nạp vào R. Tôi muốn sử dụng foreach để xử lý song song. Mã của tôi hoạt động cho một số thứ như 100 xts đối tượng mà tôi tải trước trong bộ nhớ, xuất, vv nhưng sau> 100 xts đối tượng, tôi đã đạt đến giới hạn bộ nhớ trên máy của mình.Cách khắc phục ràng buộc bộ nhớ bằng cách sử dụng foreach

Ví dụ về những gì tôi đang cố gắng để làm:

require(TTR) 
require(doMPI) 
require(foreach) 

test.data <- runif(n=250*10*60*24) 

xts.1 <- xts(test.data, order.by=as.Date(1:length(test.data))) 
xts.1 <- cbind(xts.1, xts.1, xts.1, xts.1, xts.1, xts.1) 

colnames(xts.1) <- c("Open", "High", "Low", "Close", "Volume", "Adjusted") 

print(object.size(xts.1), units="Gb") 

xts.2 <- xts.1 
xts.3 <- xts.1 
xts.4 <- xts.1 

save(xts.1, file="xts.1.rda") 
save(xts.2, file="xts.2.rda") 
save(xts.3, file="xts.3.rda") 
save(xts.4, file="xts.4.rda") 

names <- c("xts.1", "xts.2", "xts.3", "xts.4") 

rm(xts.1) 
rm(xts.2) 
rm(xts.3) 
rm(xts.4) 

cl <- startMPIcluster(count=2) # Use 2 cores 
registerDoMPI(cl) 

result <- foreach(name=names, 
        .combine=cbind, 
        .multicombine=TRUE, 
        .inorder=FALSE, 
        .packages=c("TTR")) %dopar% { 
    # TODO: Move following line out of worker. One (or 5, 10, 
    # 20, ... but not all) object at a time should be loaded 
    # by master and exported to worker "just in time" 
    load(file=paste0(name, ".rda")) 

    return(last(SMA(get(name)[, 1], 10))) 
} 

closeCluster(cl) 

print(result) 

Vì vậy, tôi tự hỏi làm thế nào tôi sẽ có thể tải từng (hoặc một vài giống như 5, 10, 20, 100, ... nhưng không phải tất cả cùng một lúc) xts đối tượng từ đĩa "chỉ trong thời gian" trước khi chúng được gửi/cần thiết bởi/xuất khẩu cho công nhân (s). Tôi không thể tải đối tượng trong công nhân (dựa trên tên và thư mục nơi nó được lưu trữ trên đĩa) vì công nhân có thể ở trên máy từ xa mà không cần truy cập vào thư mục nơi các đối tượng được lưu trữ trên đĩa. Vì vậy, tôi cần để có thể đọc/tải chúng "chỉ trong thời gian" trong quá trình chính ...

Tôi đang sử dụng doMPI và doRedis làm back-end song song. doMPI có vẻ hiệu quả hơn bộ nhớ nhưng chậm hơn so với doRedis (trên 100 đối tượng).

Vì vậy, tôi muốn hiểu "chiến lược"/"mẫu" thích hợp để tiếp cận vấn đề này là gì.

+0

Bạn có chắc chắn mã của mình bị ràng buộc CPU không? Dường như nó có thể là I/O-ràng buộc, có nghĩa là chạy trên nhiều CPU sẽ không giúp đỡ (đặc biệt là kể từ khi các công nhân không thể truy cập vào đĩa). –

+0

@JoshuaUlrich Vâng, trong thực tế tôi thực sự có kế hoạch để chạy một cái gì đó như 50 lần quantstrat :: applyIndicators và quantstrat :: applySignals. Vì vậy, các công cụ I/O có tác động, chắc chắn, nhưng tôi thực sự muốn có thể làm điều đó song song. Đây là ví dụ cho backtesting hơn 10 năm lịch sử. Trong kịch bản "thời gian thực", tôi chỉ cần tải lịch sử của các đối tượng trong khoảng thời gian nhìn lại lớn nhất từ ​​thời điểm thời gian chạy cụ thể. Tôi thực sự quan tâm nếu tải có thể được chuyển ra khỏi công nhân thành chủ và các đối tượng sau đó cung cấp từng người một (hoặc trong các nhóm quản lý) cho người lao động. – Samo

Trả lời

3

Ngoài việc sử dụng doMPI hoặc doRedis, bạn cần viết hàm trả về trình lặp thích hợp. Có một số ví dụ trong họa tiết của tôi "Viết Tuỳ chỉnh vòng lặp" từ gói lặp rằng sẽ hữu ích, nhưng đây là một nỗ lực nhanh chóng tại một buổi lễ như:

ixts <- function(xtsnames) { 
    it <- iter(xtsnames) 

    nextEl <- function() { 
    xtsname <- nextElem(it) # throws "StopIteration" 
    load(file=paste0(xtsname, ".rda")) 
    get(xtsname) 
    } 

    obj <- list(nextElem=nextEl) 
    class(obj) <- c('ixts', 'abstractiter', 'iter') 
    obj 
} 

Đây là thực sự đơn giản vì nó là cơ bản một wrapper xung quanh một trình lặp trên biến "tên". Họa tiết sử dụng kỹ thuật này cho một số ví dụ.

Bạn có thể sử dụng "ixts" với foreach như sau:

result <- foreach(xts=ixts(names), 
        .combine=cbind, 
        .multicombine=TRUE, 
        .inorder=FALSE, 
        .packages=c("TTR")) %dopar% { 
    last(SMA(xts[, 1], 10)) 
} 

Mặc dù iterator này sẽ làm việc với bất kỳ foreach phụ trợ, không phải tất cả backends sẽ gọi nó là just-in-time. doMPI và doRedis sẽ, nhưng doParallel và doMC nhận tất cả các giá trị từ trình lặp lên phía trước vì clusterApplyLB và mclapply yêu cầu các giá trị cho tất cả nằm trong một danh sách. doMPI và doRedis được thiết kế để làm việc với các trình vòng lặp để có nhiều bộ nhớ hiệu quả hơn.

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