2016-03-17 24 views
8

Tôi đang cố gắng giảm yêu cầu bộ nhớ của mã 3 python của tôi. Ngay bây giờ mỗi lần lặp của vòng lặp for đòi hỏi nhiều bộ nhớ hơn so với lần cuối cùng.Tại sao vòng lặp của tôi yêu cầu nhiều bộ nhớ hơn trên mỗi lần lặp?

Tôi đã viết một đoạn mã nhỏ mà có hành vi tương tự như dự án của tôi:

import numpy as np 
from multiprocessing import Pool 
from itertools import repeat 


def simulation(steps, y): # the function that starts the parallel execution of f() 
    pool = Pool(processes=8, maxtasksperchild=int(steps/8)) 
    results = pool.starmap(f, zip(range(steps), repeat(y)), chunksize=int(steps/8)) 
    pool.close() 
    return results 


def f(steps, y): # steps is used as a counter. My code doesn't need it. 
     a, b = np.random.random(2) 
     return y*a, y*b 

def main(): 
    steps = 2**20 # amount of times a random sample is taken 
    y = np.ones(5) # dummy variable to show that the next iteration of the code depends on the previous one 
    total_results = np.zeros((0,2)) 
    for i in range(5): 
     results = simulation(steps, y[i-1]) 
     y[i] = results[0][0] 
     total_results = np.vstack((total_results, results)) 

    print(total_results, y) 

if __name__ == "__main__": 
    main() 

Đối với mỗi lần lặp của vòng lặp for các chủ đề trong mô phỏng() mỗi người đều có một cách sử dụng bộ nhớ tương đương với tổng số bộ nhớ được sử dụng bởi mã của tôi.

Python có sao chép toàn bộ môi trường của tôi mỗi khi các tiến trình song song được chạy, bao gồm các biến không được yêu cầu bởi f()? Làm thế nào tôi có thể ngăn chặn hành vi này?

Lý tưởng nhất là tôi muốn mã của mình chỉ sao chép bộ nhớ mà nó yêu cầu để thực thi f() trong khi tôi có thể lưu kết quả vào bộ nhớ.

+0

Kết quả lớn như thế nào [0] [0]? – snakecharmerb

+0

có nó nhân bản toàn bộ ngữ cảnh của chương trình –

+0

Bạn nên bảo vệ các hoạt động chính đó với 'if __name__ == '__main __':' ít nhất. –

Trả lời

2

Mặc dù kịch bản không sử dụng khá nhiều bộ nhớ ngay cả với các ví dụ giá trị "nhỏ hơn", câu trả lời cho

Liệu Python sao chép toàn bộ môi trường của tôi mỗi lần song song tiến trình đang chạy, bao gồm các biến không yêu cầu bởi f()? Làm thế nào tôi có thể ngăn chặn hành vi này?

là nó theo một cách bản sao môi trường với forking một quá trình mới, nhưng nếu copy-on-write ngữ nghĩa có sẵn, không có bộ nhớ vật lý thực tế cần phải được sao chép cho đến khi nó được ghi vào. Ví dụ trên hệ thống này

% uname -a 
Linux mypc 4.2.0-27-generiC#32-Ubuntu SMP Fri Jan 22 04:49:08 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux 

COW có vẻ là có sẵn và được sử dụng, nhưng điều này có thể không phải là trường hợp trên các hệ thống khác. Trên Windows, điều này hoàn toàn khác với một trình thông dịch Python mới được thực thi từ .exe thay vì forking. Vì bạn đề cập đến sử dụng htop, bạn đang sử dụng một số hương vị của hệ thống UNIX hoặc UNIX giống như, và bạn nhận được COW ngữ nghĩa.

Đối với mỗi lần lặp của vòng lặp for các quá trình trong mô phỏng() mỗi có sử dụng bộ nhớ tương đương với tổng số bộ nhớ sử dụng bởi mã của tôi.

Quá trình sinh sản sẽ hiển thị các giá trị gần như giống hệt nhau của RSS, nhưng điều này có thể gây hiểu nhầm, vì phần lớn chúng chiếm cùng một bộ nhớ vật lý thực tế được ánh xạ tới nhiều quy trình, nếu viết không xảy ra. Với Pool.map câu chuyện phức tạp hơn một chút, vì nó "cho phép lặp lại thành một số khối mà nó đệ trình vào nhóm xử lý như các nhiệm vụ riêng biệt". Việc gửi này xảy ra trên IPC và dữ liệu được gửi sẽ được sao chép. Trong ví dụ của bạn, các cuộc gọi hàm IPC và 2 ** 20 cũng thống trị việc sử dụng CPU. Thay thế ánh xạ bằng một phép nhân vectơ đơn lẻ trong simulation mất thời gian chạy của tập lệnh từ khoảng 150 đến 0.66s trên máy này.

Chúng ta có thể quan sát COW với một ví dụ (hơi) đơn giản mà phân bổ một mảng lớn và chuyển nó tới một quá trình sinh ra cho read-only chế biến:

import numpy as np 
from multiprocessing import Process, Condition, Event 
from time import sleep 
import psutil 


def read_arr(arr, done, stop): 
    with done: 
     S = np.sum(arr) 
     print(S) 
     done.notify() 
    while not stop.is_set(): 
     sleep(1) 


def main(): 
    # Create a large array 
    print('Available before A (MiB):', psutil.virtual_memory().available/1024 ** 2) 
    input("Press Enter...") 
    A = np.random.random(2**28) 
    print('Available before Process (MiB):', psutil.virtual_memory().available/1024 ** 2) 
    input("Press Enter...") 
    done = Condition() 
    stop = Event() 
    p = Process(target=read_arr, args=(A, done, stop)) 
    with done: 
     p.start() 
     done.wait() 
    print('Available with Process (MiB):', psutil.virtual_memory().available/1024 ** 2) 
    input("Press Enter...") 
    stop.set() 
    p.join() 

if __name__ == '__main__': 
    main() 

Output trên máy tính này:

% python3 test.py 
Available before A (MiB): 7779.25 
Press Enter... 
Available before Process (MiB): 5726.125 
Press Enter... 
134221579.355 
Available with Process (MiB): 5720.79296875 
Press Enter... 

Bây giờ, nếu chúng tôi thay thế hàm read_arr bằng chức năng sửa đổi mảng:

def mutate_arr(arr, done, stop): 
    with done: 
     arr[::4096] = 1 
     S = np.sum(arr) 
     print(S) 
     done.notify() 
    while not stop.is_set(): 
     sleep(1) 

kết quả là hoàn toàn khác nhau:

Available before A (MiB): 7626.12109375 
Press Enter... 
Available before Process (MiB): 5571.82421875 
Press Enter... 
134247509.654 
Available with Process (MiB): 3518.453125 
Press Enter... 

Các cho vòng lặp không thực sự đòi hỏi nhiều bộ nhớ hơn sau mỗi lần lặp, nhưng đó là rõ ràng: nó ngăn xếp các total_results từ các bản đồ, vì vậy nó phải phân bổ không gian cho một mảng mới để giữ cả hai kết quả cũ và mới và miễn phí các mảng chưa được sử dụng của các kết quả cũ.

0

Có thể bạn nên biết sự khác biệt giữa threadprocess trong Operating System. xem này What is the difference between a process and a thread.

Trong vòng lặp for, có processes, không phải threads. Chủ đề chia sẻ không gian địa chỉ của quá trình tạo ra nó; các quy trình có không gian địa chỉ riêng của chúng.

Bạn có thể in id quá trình, nhập os.getpid().

+0

Nó không phải là màu đen và trắng, như tôi đã chỉ ra. Quy trình có thể chia sẻ bộ nhớ vật lý, mặc dù chúng có không gian địa chỉ riêng của chúng. –

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