จะทำโปรไฟล์กระบวนการย่อยหลายรายการโดยใช้ Python multiprocessing และ memory_profiler ได้อย่างไร

ฉันมียูทิลิตี้ที่สร้างคนงานหลายคนโดยใช้โมดูล Python multiprocessing และฉัน' ต้องการติดตามการใช้หน่วยความจำผ่านยูทิลิตี้ memory_profiler ที่ยอดเยี่ยม ซึ่งทำทุกอย่างที่ฉันต้องการ - โดยเฉพาะอย่างยิ่งการสุ่มตัวอย่างการใช้หน่วยความจำเมื่อเวลาผ่านไปและการวางแผนผลลัพธ์สุดท้าย (ฉันไม่เกี่ยวข้องกับโปรไฟล์หน่วยความจำแบบทีละบรรทัดสำหรับคำถามนี้)

เพื่อตั้งคำถามนี้ ฉันได้สร้างสคริปต์เวอร์ชันที่เรียบง่ายกว่า ซึ่งมีฟังก์ชันผู้ปฏิบัติงานซึ่งจัดสรรหน่วยความจำคล้ายกับ ตัวอย่าง ที่ให้ไว้ในไลบรารี memory_profiler คนงานมีดังนี้:

import time

X6 = 10 ** 6
X7 = 10 ** 7

def worker(num, wait, amt=X6):
    """
    A function that allocates memory over time.
    """
    frame = []

    for idx in range(num):
        frame.extend([1] * amt)
        time.sleep(wait)

    del frame

โดยกำหนดปริมาณงานตามลำดับจำนวนคนงาน 4 คน ดังนี้

if __name__ == '__main__':
    worker(5, 5, X6)
    worker(5, 2, X7)
    worker(5, 5, X6)
    worker(5, 2, X7)

การเรียกใช้ไฟล์ปฏิบัติการ mprof เพื่อสร้างโปรไฟล์สคริปต์ของฉันใช้เวลา 70 วินาทีโดยให้พนักงานแต่ละคนทำงานทีละคน สคริปต์รันดังนี้:

$ mprof run python myscript.py

สร้างกราฟการใช้หน่วยความจำต่อไปนี้:

ผู้ปฏิบัติงานสร้างหน่วยความจำตามลำดับ

การให้คนทำงานเหล่านี้ขนานกับ multiprocessing หมายความว่าสคริปต์จะเสร็จสิ้นช้าเท่ากับคนทำงานที่ช้าที่สุด (25 วินาที) สคริปต์นั้นมีดังนี้:

import multiprocessing as mp

if __name__ == '__main__':
    pool    = mp.Pool(processes=4)
    tasks   = [
        pool.apply_async(worker, args) for args in
        [(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
    ]

    results = [p.get() for p in tasks]

โปรแกรมสร้างโปรไฟล์หน่วยความจำทำงานได้จริง หรืออย่างน้อยก็ไม่มีข้อผิดพลาดเมื่อใช้ mprof แต่ผลลัพธ์ที่ได้ค่อนข้างแปลก:

ป้อนคำอธิบายรูปภาพที่นี่

การดูการตรวจสอบกิจกรรมโดยย่อแสดงให้เห็นว่าอันที่จริงมีกระบวนการ Python 6 กระบวนการ หนึ่งกระบวนการสำหรับ mprof หนึ่งกระบวนการสำหรับ python myscript.py และอีกกระบวนการหนึ่งสำหรับกระบวนการย่อยของผู้ปฏิบัติงานแต่ละคน ดูเหมือนว่า mprof กำลังวัดการใช้หน่วยความจำสำหรับกระบวนการ python myscript.py เท่านั้น

กระบวนการของ Python ในการตรวจสอบกิจกรรม

ไลบรารี memory_profiler สามารถปรับแต่งได้อย่างมาก และฉันค่อนข้างมั่นใจว่าควรจะสามารถบันทึกหน่วยความจำของแต่ละกระบวนการ และอาจเขียนลงในไฟล์บันทึกแยกกันโดยใช้ไลบรารีนั้นเอง ฉันแค่ไม่แน่ใจว่าจะเริ่มต้นจากตรงไหนหรือจะเข้าใกล้ระดับการปรับแต่งนั้นได้อย่างไร

แก้ไข

หลังจากอ่านสคริปต์ mprof แล้ว ฉันค้นพบแฟล็ก -C ซึ่งสรุปการใช้หน่วยความจำของกระบวนการย่อยทั้งหมด (แยกทาง) สิ่งนี้นำไปสู่กราฟ (ดีขึ้นมาก) ดังนี้:

ผู้ปฏิบัติงานแบบมัลติโพรเซสซิงพร้อมแฟล็กลูก

แต่สิ่งที่ฉันกำลังมองหาคือการใช้หน่วยความจำของแต่ละกระบวนการย่อยในช่วงเวลาหนึ่ง เพื่อที่ฉันจะสามารถพล็อตผู้ปฏิบัติงานทั้งหมด (และต้นแบบ) บนกราฟเดียวกันได้ ความคิดของฉันคือให้แต่ละกระบวนการย่อย memory_usage เขียนลงในไฟล์บันทึกอื่น ซึ่งฉันสามารถมองเห็นได้


person bbengfort    schedule 13.07.2016    source แหล่งที่มา
comment
คำถามนี้กำลังถูกหารือกับนักพัฒนาบน GitHub ที่ github.com/fabianp/memory_profiler/issues/118ถ้าใครสนใจ.   -  person bbengfort    schedule 16.07.2016


คำตอบ (1)


ณ วันนี้ มีการเพิ่มคุณสมบัติใหม่ลงในไลบรารีตัวสร้างโปรไฟล์หน่วยความจำที่ทำสิ่งนี้ทุกประการ หากคุณต้องการฟังก์ชันนี้ ให้อัพเดต memory_profiler ก่อนดังนี้:

$ pip install -U memory_profiler 

สิ่งนี้ควรติดตั้งตัวสร้างโปรไฟล์หน่วยความจำรุ่น v0.44 หากต้องการตรวจสอบว่าเป็นกรณีนี้ ให้ใช้คำสั่ง help ในการดำเนินการรัน:

mprof run --help
Usage: mprof run [options]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  --python              Activates extra features when the profiling executable
                        is a Python program (currently: function
                        timestamping.)
  --nopython            Disables extra features when the profiled executable
                        is a Python program (currently: function
                        timestamping.)
  -T INTERVAL, --interval=INTERVAL
                        Sampling period (in seconds), defaults to 0.1
  -C, --include-children
                        Monitors forked processes as well (sum up all process
                        memory)
  -M, --multiprocess    Monitors forked processes creating individual plots
                        for each child

หากคุณเห็นธง -M แสดงว่าคุณพร้อมแล้ว!

จากนั้นคุณสามารถเรียกใช้สคริปต์ของคุณได้ดังนี้:

$ mprof run -M python myscript.py
$ mprof plot 

และคุณควรจะได้รูปที่มีลักษณะดังนี้:

mprof ติดตามกระบวนการย่อยแต่ละรายการ

โปรดทราบว่าหากคุณใช้แฟล็ก --include-children เช่นกัน หน่วยความจำกระบวนการหลักจะเป็นการใช้หน่วยความจำรวมของรายการย่อยและรายการหลักทั้งหมด ซึ่งเป็นพล็อตที่เป็นประโยชน์เช่นกัน

person bbengfort    schedule 22.03.2017
comment
ขอขอบคุณเป็นพิเศษสำหรับ @fabian-pedregosa ที่ช่วยทำให้สิ่งนี้เกิดขึ้น! - person bbengfort; 22.03.2017
comment
ลองเปิดใช้งานการประทับเวลาและ @profile มัณฑนากรในโหมดนี้ดูไหม เป็นไปได้ไหม? - person petroslamb; 01.06.2017
comment
ฉันไม่แน่ใจว่าคุณหมายถึงอะไรเกี่ยวกับการเปิดใช้งานการประทับเวลา ฉันคิดว่าสิ่งนี้น่าจะเป็นไปได้ด้วย @profile มัณฑนากร ซึ่งใช้อาร์กิวเมนต์เดียวกัน - person bbengfort; 05.06.2017
comment
น่าเสียดายที่ฉันไม่สามารถทำงานได้ โปรดดูที่ github.com/fabianp/memory_profiler/issues/148 - person petroslamb; 06.06.2017
comment
อ๋อ ฉันเห็นปัญหาแล้ว นั่นเป็นรายงานข้อผิดพลาดที่ดีมากเลย น่าเสียดายที่ปัญหาของดองเกิดขึ้นทุกที่เมื่อต้องจัดการกับโปรไฟล์หลายกระบวนการประเภทต่างๆ ขอโทษด้วยกับเรื่องนั้น. - person bbengfort; 07.06.2017
comment
มีวิธีตั้งชื่อสำหรับกระบวนการลูกหรือไม่? child-n ไม่ได้อธิบายจริงๆ :) - person Alon Gouldman; 07.04.2020
comment
คงจะดีไม่น้อยหากมีวิธีใดทางหนึ่ง ฉันคิดว่าคุณอาจต้องลงลึกในรายละเอียดของ cprofile เพื่อดูว่ามีวิธีใดบ้างในการทำเช่นนั้น - person bbengfort; 07.04.2020
comment
@ fabian-pedregosa เราสามารถบันทึกพล็อตนี้โดยอัตโนมัติได้หรือไม่? - person Pe Dro; 03.06.2020
comment
ฉันพบแพ็กเกจ TAMPPA สำหรับบันทึกผลลัพธ์ของ memory-profiler และ line-profiler เป็น csv .. ดีสำหรับใช้ในอนาคต :) หวังว่าจะช่วยได้ - person Pe Dro; 29.08.2020