2011-07-10 25 views
10

Vì vậy, scala 2.9 gần đây được bật lên trong thử nghiệm Debian, đưa các bộ sưu tập song song mới lạ với nó.Đối phó với sự thiếu hụt đáng ngạc nhiên của ParList trong scala.collections.parallel

Giả sử tôi có một số mã tương đương với

def expensiveFunction(x:Int):Int = {...} 

    def process(s:List[Int]):List[Int} = s.map(expensiveFunction) 

bây giờ từ các bit teeny tôi đã lượm lặt về bộ sưu tập song song trước khi các tài liệu thực sự bật lên trên máy tính của tôi, tôi đã mong parallelize này chỉ bằng cách chuyển Liệt kê một số ParList ... nhưng với sự ngạc nhiên của tôi, không có một! (Chỉ cần ParVector, ParMap, ParSet ...).

Là một workround, đây (hoặc một dòng tương đương) dường như làm việc tốt đủ:

def process(s:List[Int]):List[Int} = { 
    val ps=scala.collection.parallel.immutable.ParVector()++s 
    val pr=ps.map(expensiveFunction) 
    List()++pr 
    } 

năng suất một sự cải tiến hiệu suất x3 xấp xỉ trong mã thử nghiệm của tôi và đạt được sử dụng CPU ồ ạt cao (lõi tứ cộng siêu phân luồng i7). Nhưng nó có vẻ hơi vụng về.

Câu hỏi của tôi là một loại của một tổng hợp:

  • Tại sao không phải là có một ParList?
  • Do không có ParList, có một mẫu tốt hơn/thành ngữ mà tôi nên áp dụng để Tôi không cảm thấy như chúng bị thiếu?
  • Tôi chỉ là "đằng sau những lần" sử dụng Danh sách rất nhiều trong các chương trình scala tôi (giống như tất cả những cuốn sách Scala tôi mua lại trong 2,7 ngày đã dạy cho tôi) và Tôi thực sự nên được tận dụng nhiều hơn của Vectors? (Tôi có nghĩa là trong C + + đất Tôi thường cần một lý do khá tốt để sử dụng std::list trên std::vector).

Trả lời

8

Đầu tiên, hãy để tôi chỉ cho bạn cách để tạo ra một phiên bản song song mã mà:

def expensiveFunction(x:Int):Int = {...} 

def process(s:List[Int]):Seq[Int] = s.par.map(expensiveFunction).seq 

Điều đó sẽ có con số Scala thứ ra cho bạn - và, bằng cách này, nó sử dụng ParVector. Nếu bạn thực sự muốn List, hãy gọi .toList thay vì .seq.

Đối với các câu hỏi sau:

  • Không có một ParList vì một List là một cấu trúc dữ liệu về bản chất không song song, bởi vì bất kỳ hoạt động trên nó đòi hỏi traversal.

  • Bạn nên mã hóa các đặc điểm thay vì các lớp - Ví dụ: Seq, ParSeqGenSeq. Ngay cả đặc tính hiệu suất của một List được đảm bảo bởi LinearSeq.

  • Tất cả sách trước Scala 2.8 không có thư viện bộ sưu tập mới. Đặc biệt, các bộ sưu tập thực sự không chia sẻ một API nhất quán và đầy đủ. Bây giờ họ làm, và bạn sẽ đạt được nhiều bằng cách tận dụng nó.

    Hơn nữa, không có bộ sưu tập nào như Vector trong Scala 2.7 - bộ sưu tập bất biến với quyền truy cập được lập chỉ mục liên tục.

14

List s là điều tuyệt vời khi bạn muốn đối sánh mẫu (ví dụ: case x :: xs) và để lập lại/lặp lại hiệu quả. Tuy nhiên, chúng không tuyệt vời như vậy khi bạn muốn truy cập nhanh theo chỉ mục hoặc chia nhỏ thành các phần hoặc tham gia (ví dụ: xs ::: ys).

Do đó nó không có ý nghĩa nhiều (để có song song List) khi bạn nghĩ rằng loại điều này (tách và nối) là chính xác điều cần thiết cho tính song song hiệu quả. Sử dụng:

xs.toIndexedSeq.par 
7

A List không thể dễ dàng chia thành nhiều danh sách phụ khác nhau khiến khó có thể song song. Đối với một, nó có O (n) truy cập; cũng là một List không thể cắt đuôi của nó, vì vậy cần phải bao gồm một tham số chiều dài.

Tôi đoán, lấy Vector sẽ là giải pháp tốt hơn.

Lưu ý rằng sốcủa Scala khác với std::vector. Sau này về cơ bản là một trình bao bọc xung quanh mảng tiêu chuẩn, một khối tiếp giáp trong bộ nhớ cần phải được sao chép mọi lúc và sau đó khi thêm hoặc xóa dữ liệu. Vector của Scala là cấu trúc dữ liệu chuyên biệt cho phép sao chép và tách hiệu quả trong khi vẫn giữ nguyên dữ liệu không thay đổi.

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