2017-05-04 26 views
6

Có an toàn không, để chia sẻ một mảng giữa các lời hứa như tôi đã làm nó trong đoạn mã sau?Có an toàn không, để chia sẻ một mảng giữa các chủ đề?

#!/usr/bin/env perl6 
use v6; 

sub my_sub ($string, $len) { 
    my ($s, $l); 
    if $string.chars > $len { 
     $s = $string.substr(0, $len); 
     $l = $len; 
    } 
    else { 
     $s = $string; 
     $l = $s.chars; 
    } 
    return $s, $l; 
} 

my @orig = <length substring character subroutine control elements now promise>; 
my $len = 7; 
my @copy; 
my @length; 
my $cores = 4; 
my $p = @orig.elems div $cores; 
my @vb = (0..^$cores).map: { [ $p * $_, $p * ($_ + 1) ] }; 
@vb[@vb.end][1] = @orig.elems; 

my @promise; 
for @vb -> $r { 
    @promise.push: start { 
     for $r[0]..^$r[1] -> $i { 
      (@copy[$i], @length[$i]) = my_sub(@orig[$i], $len); 
     } 
    }; 
} 
await @promise; 
+0

Toàn bộ điểm hứa hẹn là lời hứa trả lại một cái gì đó, bạn không cố ý trả lại bất kỳ điều gì hữu ích từ tiền tố câu lệnh 'start'. –

+0

Nhưng 'bắt đầu' làm nhiều hơn thì chỉ trả lại một cái gì đó. Tôi quan tâm đến một phần đồng thời để chạy mã song song để tất cả các lõi CPU của tôi phải làm việc. –

+1

Những gì tôi đang nói là giống như chọn lên một cờ lê, và sau đó sử dụng nó để đập trong một móng tay. Làm việc, ... tôi đoán vậy. –

Trả lời

14

Nó phụ thuộc vào cách bạn xác định "mảng" và "chia sẻ".Cho đến khi mảng đi, có hai trường hợp cần phải được xem xét riêng:

  • Mảng kích thước cố định (được khai báo my @a[$size]); điều này bao gồm các mảng đa chiều với kích thước cố định (chẳng hạn như my @a[$xs, $ys]). Đây là những tài sản thú vị mà bộ nhớ sao lưu chúng không bao giờ phải được thay đổi kích cỡ.
  • Mảng động (được khai báo my @a), phát triển theo yêu cầu. Đây là, dưới mui xe, thực sự sử dụng một số khối bộ nhớ theo thời gian khi chúng phát triển.

Cho đến nay như chia sẻ đi, cũng có ba trường hợp:

  • Các trường hợp nhiều luồng chạm vào mảng trên cuộc đời của mình, nhưng chỉ có ai có thể chạm vào nó tại một thời điểm, do một số cơ chế điều khiển đồng thời hoặc cấu trúc chương trình tổng thể. Trong trường hợp này, các mảng không bao giờ được chia sẻ theo nghĩa "các hoạt động đồng thời sử dụng các mảng", do đó không có khả năng có một cuộc đua dữ liệu.
  • Trường hợp chỉ đọc, không lười. Đây là nơi nhiều hoạt động đồng thời truy cập một mảng không phải là lười, nhưng chỉ đọc nó.
  • Trường hợp đọc/ghi (bao gồm khi đọc thực sự gây ra ghi vì mảng đã được gán thứ gì đó yêu cầu đánh giá lười biếng; lưu ý điều này không bao giờ có thể xảy ra với mảng kích thước cố định vì chúng không bao giờ lười).

Sau đó chúng ta có thể tóm tắt sự an toàn như sau:

     | Fixed size  | Variable size | 
---------------------+----------------+---------------+ 
Read-only, non-lazy | Safe   | Safe   | 
Read/write or lazy | Safe *   | Not safe  | 

Các * cho thấy sự báo trước rằng trong khi nó an toàn từ quan điểm của Perl 6, bạn dĩ nhiên phải chắc chắn rằng bạn không làm những điều xung đột với cùng một chỉ số.

Vì vậy, tóm lại, mảng kích thước cố định bạn có thể chia sẻ và gán một cách an toàn cho các phần tử khác nhau "không có vấn đề" (nhưng hãy giả sử chia sẻ sai, có thể khiến bạn phải trả một khoản phạt nặng để thực hiện). Đối với mảng động, nó chỉ an toàn nếu chúng chỉ được đọc từ trong thời gian chúng được chia sẻ, và thậm chí nếu chúng không lười (mặc dù gán mảng hầu hết là háo hức, bạn không có khả năng đánh vào tình huống đó vô tình). Viết, ngay cả với các yếu tố khác nhau, rủi ro mất dữ liệu, sự cố hoặc hành vi xấu khác do hoạt động ngày càng tăng.

Vì vậy, xem xét ví dụ ban đầu, chúng ta thấy my @copy;my @length; là mảng động, vì vậy chúng tôi không được viết cho chúng trong các hoạt động đồng thời. Tuy nhiên, điều đó xảy ra, do đó, mã có thể được xác định không an toàn.

Các bài đăng khác đã có ở đây thực hiện một công việc tốt về chỉ đường theo hướng tốt hơn, nhưng không có gì đóng góp chi tiết đẫm máu.

5

Chỉ cần có mã được đánh dấu với tiền tố start tuyên bố trả lại giá trị để Perl 6 có thể xử lý đồng bộ cho bạn. Đó là toàn bộ điểm của tính năng đó.
Sau đó, bạn có thể đợi tất cả các Lời hứa và nhận tất cả các kết quả bằng cách sử dụng câu lệnh await.

my @promise = do for @vb -> $r { 

    start 

     do # to have the 「for」 block return its values 

     for $r[0]..^$r[1] -> $i { 
      $i, my_sub(@orig[$i], $len) 
     } 
} 

my @results = await @promise; 

for @results -> ($i,$copy,$len) { 
    @copy[$i] = $copy; 
    @length[$i] = $len; 
} 

Các start tuyên bố tiền tố là chỉ sắp xếp của tiếp tuyến liên quan đến xử lý song song.
Khi bạn sử dụng nó, bạn đang nói, "Tôi không cần những kết quả này ngay bây giờ, nhưng có lẽ sẽ sau này".

Đó là lý do nó trả về một Promise (không đồng), và không phải là một Thread (đồng thời)

Bộ thực thi được phép trì hoãn thực sự chạy mã đó cho đến khi bạn cuối cùng đã yêu cầu kết quả, và thậm chí sau đó nó có thể chỉ làm tất cả chúng tuần tự trong cùng một chuỗi.

Nếu việc thực hiện thực sự đã làm điều đó, nó có thể dẫn đến một cái gì đó giống như một bế tắc nếu bạn thay vì thăm dò ý kiến ​​các Promise bằng cách liên tục gọi nó .status phương pháp chờ đợi cho nó để thay đổi Planned-Kept hoặc Broken, và chỉ sau đó yêu cầu kết quả của nó .
Đây là một phần lý do khiến trình lên lịch mặc định sẽ bắt đầu hoạt động trên mọi mã Promise nếu có bất kỳ chuỗi dự phòng nào.


Tôi khuyên bạn nên xem bài nói chuyện của jnthn “Parallelism, Concurrency, and Asynchrony in Perl 6”.
slides

+0

Trả về các giá trị (để sử dụng 'await') và sau đó sao chép các giá trị vào đúng nơi đã làm cho nó chậm hơn một chút. Ngoài ra sau đó mã là khó khăn hơn để đọc cho tôi. Tôi đã cố gắng sử dụng giao diện 'Thread'; Tôi không thấy tăng tốc độ nào và mức độ thấp hơn. –

+0

@sid_com Đặt nó vào trong mảng khiến nó phải đợi trước các quy trình vòng lặp. Nếu bạn chỉ cần đặt 'await' trong vòng lặp' for' trong đó '@ results' là, nó sẽ bắt đầu xử lý các giá trị trước khi chúng được thực hiện xong. –

4

Câu trả lời này áp dụng cho sự hiểu biết của tôi về tình hình trên MoarVM, không chắc chắn về trạng thái của chương trình phụ trợ JVM (hoặc phần phụ trợ Javascript fwiw).

  • Đọc một vô hướng từ một số chủ đề có thể được thực hiện một cách an toàn.
  • Sửa đổi một vô hướng từ một số chủ đề có thể được thực hiện mà không cần phải lo sợ cho một segfault, nhưng bạn có thể bỏ lỡ cập nhật:

$ perl6 -e 'my $i = 0; await do for ^10 { start { $i++ for ^10000 } }; say $i' 46785

cũng áp dụng cho các cấu trúc dữ liệu phức tạp hơn như mảng (ví dụ mất tích giá trị được đẩy) và băm (thiếu các khóa được thêm).

Vì vậy, nếu bạn không nhớ thiếu thông tin cập nhật, việc thay đổi cấu trúc dữ liệu được chia sẻ từ một số chuỗi sẽ hoạt động. Nếu bạn không quan tâm đến các cập nhật, mà tôi nghĩ là những gì bạn thường muốn, bạn nên xem xét thiết lập thuật toán của mình theo một cách khác, như được đề xuất bởi @Zoffix Znet và @raiph.

-1

số





Nghiêm túc. Các câu trả lời khác dường như đưa ra quá nhiều giả định về việc triển khai, không có câu nào trong số đó được kiểm tra bởi spec.

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