Biến toàn cục đa xử lý Python

Trong bài đăng này, chúng tôi nói về cách sao chép dữ liệu từ quy trình gốc sang một số quy trình worker trong

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
9 bằng cách sử dụng các biến toàn cục. Cụ thể, chúng tôi sẽ sử dụng các thuộc tính lớp, vì tôi thấy giải pháp này hấp dẫn hơn một chút so với sử dụng các biến toàn cục được xác định ở đầu tệp

Đối với những bạn mới tham gia loạt bài này, vấn đề chúng tôi đang cố gắng giải quyết như sau…

Cho lớp sau

class IntToBitarrayConverter[]:
    
    def set_bitstring_cache[self, bitstring_cache: Dict]:
        self.bitstring_cache = bitstring_cache

    def convert[self, integer: int] -> np.ndarray:
        bitstring = self.bitstring_cache[integer]
        # cache the step of bitstring = format[integer, 'b']
        return self._bitstring_to_ndarray[bitstring]

    @staticmethod
    def _bitstring_to_ndarray[bitstring] -> np.ndarray:
        arr = [np.fromstring[bitstring, 'u1'] - 48]
        return arr

Và đưa ra sự song song sau đây của phương pháp

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
0 của chúng tôi bằng cách sử dụng
CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
1

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]

Chúng tôi đã học được rằng khi bạn có một phương thức thể hiện với một đối tượng lớn được liên kết với nó, việc chuyển phương thức này sang

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
2 sẽ dẫn đến mất hiệu suất rất lớn do lặp lại quá trình tuần tự hóa/giải tuần tự hóa đối tượng lớn giữa các quy trình

Đây là những gì đã xảy ra với phương pháp

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
0 của chúng tôi ở trên. Trong bài đăng này, chúng tôi khám phá một giải pháp chỉ cho chúng tôi “cách truyền dữ liệu đến Nhóm công nhân và chỉ thực hiện một lần. ”

Một giải pháp sang trọng

Câu trả lời đáng tiếc cho câu hỏi của chúng tôi ở trên là, với cách triển khai hiện tại của

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
1, chúng tôi cần sử dụng các biến toàn cục để truyền dữ liệu tới
CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
5 của chúng tôi. Hầu hết các tài nguyên liên mạng sẽ cho bạn thấy ví dụ tương tự này

Bằng cách thực hiện một cách tiếp cận khác, chúng ta có thể phân loại điều này một chút bằng cách sử dụng các thuộc tính lớp và một

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
0, với hy vọng rằng chúng ta có thể bảo tồn một cách tinh vi một số hình thức đóng gói trong mã của mình

Nhập

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
1

class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]

Chúng tôi kế thừa từ

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
2 và thực hiện ba thay đổi

  1. CACHE_SIZE = 1024 * 1024  # 1 MB
    ITER_SIZE = 1000000  # 1 million
    
    int_to_bitarr_converter = IntToBitarrayConverter[]
    int_to_bitarr_converter.set_bitstring_cache[
        {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
    with Pool[] as pool:
        ndarray_bitarr_ls = pool.map[
            int_to_bitarr_converter.convert,
            [random.randint[0, CACHE_SIZE - 1]
             for _ in range[ITER_SIZE]]]]
    
    3 trở thành một thuộc tính của lớp
  2. CACHE_SIZE = 1024 * 1024  # 1 MB
    ITER_SIZE = 1000000  # 1 million
    
    int_to_bitarr_converter = IntToBitarrayConverter[]
    int_to_bitarr_converter.set_bitstring_cache[
        {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
    with Pool[] as pool:
        ndarray_bitarr_ls = pool.map[
            int_to_bitarr_converter.convert,
            [random.randint[0, CACHE_SIZE - 1]
             for _ in range[ITER_SIZE]]]]
    
    0 trở thành một
    CACHE_SIZE = 1024 * 1024  # 1 MB
    ITER_SIZE = 1000000  # 1 million
    
    int_to_bitarr_converter = IntToBitarrayConverter[]
    int_to_bitarr_converter.set_bitstring_cache[
        {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
    with Pool[] as pool:
        ndarray_bitarr_ls = pool.map[
            int_to_bitarr_converter.convert,
            [random.randint[0, CACHE_SIZE - 1]
             for _ in range[ITER_SIZE]]]]
    
    0
  3. CACHE_SIZE = 1024 * 1024  # 1 MB
    ITER_SIZE = 1000000  # 1 million
    
    int_to_bitarr_converter = IntToBitarrayConverter[]
    int_to_bitarr_converter.set_bitstring_cache[
        {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
    with Pool[] as pool:
        ndarray_bitarr_ls = pool.map[
            int_to_bitarr_converter.convert,
            [random.randint[0, CACHE_SIZE - 1]
             for _ in range[ITER_SIZE]]]]
    
    6 trở thành một
    CACHE_SIZE = 1024 * 1024  # 1 MB
    ITER_SIZE = 1000000  # 1 million
    
    int_to_bitarr_converter = IntToBitarrayConverter[]
    int_to_bitarr_converter.set_bitstring_cache[
        {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
    with Pool[] as pool:
        ndarray_bitarr_ls = pool.map[
            int_to_bitarr_converter.convert,
            [random.randint[0, CACHE_SIZE - 1]
             for _ in range[ITER_SIZE]]]]
    
    0

Ghi chú. Những gì chúng tôi đã làm ở đây về cơ bản là gói 2 hàm toàn cục, với 1 biến toàn cục và cùng định vị chúng trong cùng một

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
8. Điều này đang lặng lẽ tiếp cận mô hình chống đơn lẻ, nhưng tôi thích sự đóng gói ở đây hơn toàn cầu, mặc dù nó là một mặt tiền nguy hiểm…

Bây giờ, khi chúng tôi chạy mã song song ở trên, vì

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
9 và
class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
0 là các toàn cầu được tôn vinh, nên
CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
0 có quyền truy cập vào
CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
3, mà không cần bất kỳ yêu cầu tuần tự hóa/giải tuần tự hóa nào, trong mỗi Quy trình
class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
3

So với 32. 5s trong lần triển khai trước đây của chúng tôi, giải pháp toàn cầu cao cấp của chúng tôi chỉ chạy trong 5s

Ghi chú. Nếu bạn đã , bạn sẽ nhận thấy rằng đây là hiệu suất tương tự như mã tuần tự, không song song của chúng tôi. Điều này là do phương pháp

CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
0 không sử dụng nhiều CPU. Đây là một chủ đề cho một bài viết khác

Chúng tôi thấy trong các cuộc gọi được định hình tới

class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
5 và
class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
6

Processdumps[] calldumps[] time[s]avgloads[] callloads[] time[s]avgParent424. 09s. 09s337. 36s. 13s1410. 34s2. 57s5. 04s. 008s2410. 31s2. 57s5. 04s. 008s3410. 31s2. 57s5. 04s. 008s4410. 36s2. 58s5. 04s. 008s5410. 23s2. 55s5. 04s. 008s6410. 19s2. 54s5. 04s. 008s7410. 04s2. 52s5. 04s. 008s849. 88s2. 47s5. 04s. 008s

Giảm thiểu mối quan tâm toàn cầu

Triển khai mới của chúng tôi ở trên được gói gọn trong một lớp, đó là một Lập trình hướng đối tượng đảm nhận toàn cầu. Tuy nhiên, theo ý kiến ​​​​của tôi, nó rõ ràng hơn là xác định biến toàn cục trong phạm vi lồng nhau, như một số bài đăng đề xuất

Các thuộc tính của lớp vẫn là các biến toàn cục, nhưng ít nhất chúng được gói gọn ở một mức độ nào đó và chỉ có sẵn dưới dạng các thuộc tính trên lớp, so với. bất cứ nơi nào. Điều này sẽ trả cổ tức khi cố gắng gỡ lỗi và duy trì cơ sở mã này, vì chỉ các mô-đun phụ thuộc vào lớp này mới cố gắng truy cập vào biến này

Đề xuất phi toàn cầu

Bất chấp những lời chỉ trích của tôi về toàn cầu đối với trường hợp sử dụng cụ thể này, câu hỏi “liệu ​​toàn cầu có xấu không” không có câu trả lời rõ ràng và phụ thuộc vào ngữ cảnh sử dụng. Mọi người cũng rất có ý kiến ​​về chủ đề này. xem bài SO này

Điều đó nói rằng, lời chỉ trích của tôi là người dùng Python không nên bị buộc phải sử dụng toàn cục hoặc thậm chí là từ khóa

class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
7 để sử dụng API
CACHE_SIZE = 1024 * 1024  # 1 MB
ITER_SIZE = 1000000  # 1 million

int_to_bitarr_converter = IntToBitarrayConverter[]
int_to_bitarr_converter.set_bitstring_cache[
    {key: format[key, 'b'] for key in range[CACHE_SIZE]}]
with Pool[] as pool:
    ndarray_bitarr_ls = pool.map[
        int_to_bitarr_converter.convert,
        [random.randint[0, CACHE_SIZE - 1]
         for _ in range[ITER_SIZE]]]]
1

Tôi đã đề xuất một tiện ích mở rộng đã được thử nghiệm tốt, tương thích ngược của API

class ClassMethodBitarrayConverter[IntToBitarrayConverter]:
    bitstring_cache = None

    @classmethod
    def set_bitstring_cache[cls, bitstring_cache: Dict]:
        cls.bitstring_cache = bitstring_cache

    @classmethod
    def convert[cls, integer: int, init_return=None] -> np.ndarray:
        bitstring = cls.bitstring_cache[integer]
        return cls._bitstring_to_ndarray[bitstring]
9 cho phép giải pháp phi toàn cầu cho vấn đề truyền dữ liệu tới và khởi tạo các quy trình của Pool worker

Các biến toàn cầu có được chia sẻ giữa các quy trình không?

Các biến toàn cục chỉ có thể được chia sẻ hoặc kế thừa bởi các quy trình con được rẽ nhánh từ quy trình mẹ . Cụ thể, điều này có nghĩa là bạn phải tạo các tiến trình con bằng cách sử dụng phương thức bắt đầu 'fork'.

Python có bộ nhớ dùng chung đa xử lý không?

Python cung cấp khả năng tạo và quản lý các quy trình mới thông qua tính năng đa xử lý. lớp quy trình. Trong lập trình đa xử lý, chúng ta thường cần chia sẻ dữ liệu và trạng thái chương trình giữa các quy trình. Điều này có thể đạt được bằng cách sử dụng bộ nhớ dùng chung thông qua các kiểu chữ dùng chung .

Python xử lý đa xử lý như thế nào?

Đa xử lý Python Lớp quy trình là một phần trừu tượng thiết lập một quy trình Python khác, cung cấp cho nó khả năng chạy mã và cách để ứng dụng mẹ kiểm soát việc thực thi. There are two important functions that belongs to the Process class - start[] and join[] function.

Đa xử lý có phải là Python song song không?

Đa xử lý Python. Xử lý song song dựa trên quy trình trong Python . Vì lý do này, Tính năng đa xử lý của Python thực hiện tính song song dựa trên quy trình .

Chủ Đề