簡體   English   中英

如何優化代碼減少memory的使用Python

[英]How to optimize the code and reduce memory usage Python

目的是減少memory 的使用 這意味着它應該以hash等於test hash的方式進行優化。

到目前為止我已經嘗試過:

  1. 添加__slots__但它沒有進行任何更改。
  2. 將默認dtype float64更改為float32 雖然它顯着減少了內存使用,但它通過更改 hash 來阻止測試。
  3. 將數據轉換為np.array減少了 CPU 時間: from 13 s to 2.05 s ,但不影響memory 的使用

要重現的代碼:

rows = 40000000
trs = 10

random.seed(42)

generated_data: tp.List[float] = np.array([random.random() for _ in range(rows)])



def df_upd(df_initial: pd.DataFrame, df_new: pd.DataFrame) -> pd.DataFrame:
    return pd.concat((df_initial, df_new), axis=1)


class T:
    """adding a column of random data"""
    __slots__ = ['var']
    def __init__(self, var: float):
        self.var = var

    def transform(self, df_initial: pd.DataFrame) -> pd.DataFrame:
        return df_upd(df_initial, pd.DataFrame({self.var: generated_data}))


class Pipeline:
    __slots__ = ['df', 'transforms']
    def __init__(self):
        self.df = pd.DataFrame()
        self.transforms = np.array([T(f"v{i}") for i in range(trs)])

    def run(self):
        for t in self.transforms:
            self.df = t.transform(self.df)
        return self.df


if __name__ == "__main__":
    
    
    # starting the monitoring
    tracemalloc.start()

    # function call
    pipe = Pipeline()
    %time df = pipe.run()
    print("running")

    # displaying the memory
    current, peak = tracemalloc.get_traced_memory()
    print(f"Current memory usage is {current / 10**3} KB ({(current / 10**3)*0.001} MB); Peak was {peak / 10**3} KB ({(peak / 10**3)*0.001} MB); Diff = {(peak - current) / 10**3} KB ({((peak - current) / 10**3)*0.001} MB)")

    # stopping the library
    tracemalloc.stop()
    
    # should stay unchanged
    %time hashed_df = hashlib.sha256(pd.util.hash_pandas_object(df, index=True).values).hexdigest()
    print("hashed_df", hashed_df)    
    
    assert hashed_df == test_hash

    print("Success!")

如果您避免pd.concat()並使用增強數據幀的首選方式:

df["new_col_name"] = new_col_data

這將顯着減少峰值 memory 的消耗。


在您的代碼中修復Transform class 就足夠了:

class Transform:
    """adding a column of random data"""
    __slots__ = ['var']
    def __init__(self, var: str):
        self.var = var

    def transform(self, df: pd.DataFrame) -> pd.DataFrame:
        df[self.var] = generated_data
        return df

(請注意,我還將vartypefloat更改為str以反映它在代碼中的使用方式)。


在我的機器中,我從:

當前 memory 使用量為 1600110.987 KB (1600.110987 MB); 峰值為 4480116.325 KB (4480.116325 MB); 差異 = 2880005.338 KB (2880.005338 MB)

到:

當前 memory 使用量為 1760101.105 KB (1760.101105 MB); 峰值為 1760103.477 KB (1760.1034769999999 MB); 差異 = 2.372 KB (0.002372 MB)

(我不確定為什么在這種情況下當前 memory 的使用率略高)。


為了加快計算速度,您可能需要進行一些預分配。

為此,您可以在 Pipeline 的__init__()中替換:

self.df = pd.DataFrame()

和:

self.df = pd.DataFrame(data=np.empty((rows, trs)), columns=[f"v{i}" for i in range(trs)])

如果你想變得更快,你可以立即在管道的__init__中計算 DataFrame ,例如:

class Pipeline:
    __slots__ = ['df', 'transforms']
    def __init__(self):
        self.df = pd.DataFrame(data=generated_data[:, None] + np.zeros(trs)[None, :], columns=[f"v{i}" for i in range(trs)])

    def run(self):
        return self.df

但我假設你的Transform是一個更復雜操作的代理,我不確定這種簡化是否容易適應問題中的玩具代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM