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ũ.
Kết quả lớn như thế nào [0] [0]? – snakecharmerb
có nó nhân bản toàn bộ ngữ cảnh của chương trình –
Bạn nên bảo vệ các hoạt động chính đó với 'if __name__ == '__main __':' ít nhất. –