亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

建議為類型化的內存視圖分配內存的方法是什么?

建議為類型化的內存視圖分配內存的方法是什么?

慕絲7291255 2019-12-12 14:06:55
有關類型化內存視圖的Cython文檔列出了分配給類型化內存視圖的三種方式:從原始的C指針從np.ndarray和從cython.view.array。假設我沒有從外部將數據傳遞到cython函數中,而是想分配內存并將其返回為np.ndarray,那么我選擇了哪些選項?還要假設該緩沖區的大小不是編譯時常量,即我無法在堆棧上分配,但需要malloc為選項1 分配。因此,這三個選項看起來像這樣:from libc.stdlib cimport malloc, freecimport numpy as npfrom cython cimport viewnp.import_array()def memview_malloc(int N):    cdef int * m = <int *>malloc(N * sizeof(int))    cdef int[::1] b = <int[:N]>m    free(<void *>m)def memview_ndarray(int N):    cdef int[::1] b = np.empty(N, dtype=np.int32)def memview_cyarray(int N):    cdef int[::1] b = view.array(shape=(N,), itemsize=sizeof(int), format="i")使我感到驚訝的是,在所有這三種情況下,Cython都會為內存分配生成大量代碼,尤其是對的調用__Pyx_PyObject_to_MemoryviewSlice_dc_int。這表明(我可能錯了,我對Cython內部工作的了解非常有限)它首先創建了一個Python對象,然后將其“投射”到內存視圖中,這似乎是不必要的開銷。一個簡單的基準測試并不能揭示這三種方法之間的太大差異,其中2.是最快的方法。建議使用三種方法中的哪一種?還是有其他更好的選擇?后續問題:np.ndarray在函數中使用該內存視圖后,我想最終將結果返回為。類型化的內存視圖是最佳選擇,還是我寧愿只使用如下所示的舊緩沖區接口來創建一個ndarray?cdef np.ndarray[DTYPE_t, ndim=1] b = np.empty(N, dtype=np.int32)
查看完整描述

2 回答

?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

看看這里的回答。


基本思想是您想要cpython.array.array和cpython.array.clone(不是 cython.array.*):


from cpython.array cimport array, clone


# This type is what you want and can be cast to things of

# the "double[:]" syntax, so no problems there

cdef array[double] armv, templatemv


templatemv = array('d')


# This is fast

armv = clone(templatemv, L, False)

編輯


事實證明,該線程中的基準是垃圾。這是我的設定,以及我的時間安排:


# cython: language_level=3

# cython: boundscheck=False

# cython: wraparound=False


import time

import sys


from cpython.array cimport array, clone

from cython.view cimport array as cvarray

from libc.stdlib cimport malloc, free

import numpy as numpy

cimport numpy as numpy


cdef int loops


def timefunc(name):

    def timedecorator(f):

        cdef int L, i


        print("Running", name)

        for L in [1, 10, 100, 1000, 10000, 100000, 1000000]:

            start = time.clock()

            f(L)

            end = time.clock()

            print(format((end-start) / loops * 1e6, "2f"), end=" ")

            sys.stdout.flush()


        print("μs")

    return timedecorator


print()

print("INITIALISATIONS")

loops = 100000


@timefunc("cpython.array buffer")

def _(int L):

    cdef int i

    cdef array[double] arr, template = array('d')


    for i in range(loops):

        arr = clone(template, L, False)


    # Prevents dead code elimination

    str(arr[0])


@timefunc("cpython.array memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr

    cdef array template = array('d')


    for i in range(loops):

        arr = clone(template, L, False)


    # Prevents dead code elimination

    str(arr[0])


@timefunc("cpython.array raw C type")

def _(int L):

    cdef int i

    cdef array arr, template = array('d')


    for i in range(loops):

        arr = clone(template, L, False)


    # Prevents dead code elimination

    str(arr[0])


@timefunc("numpy.empty_like memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr

    template = numpy.empty((L,), dtype='double')


    for i in range(loops):

        arr = numpy.empty_like(template)


    # Prevents dead code elimination

    str(arr[0])


@timefunc("malloc")

def _(int L):

    cdef int i

    cdef double* arrptr


    for i in range(loops):

        arrptr = <double*> malloc(sizeof(double) * L)

        free(arrptr)


    # Prevents dead code elimination

    str(arrptr[0])


@timefunc("malloc memoryview")

def _(int L):

    cdef int i

    cdef double* arrptr

    cdef double[::1] arr


    for i in range(loops):

        arrptr = <double*> malloc(sizeof(double) * L)

        arr = <double[:L]>arrptr

        free(arrptr)


    # Prevents dead code elimination

    str(arr[0])


@timefunc("cvarray memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr


    for i in range(loops):

        arr = cvarray((L,),sizeof(double),'d')


    # Prevents dead code elimination

    str(arr[0])




print()

print("ITERATING")

loops = 1000


@timefunc("cpython.array buffer")

def _(int L):

    cdef int i

    cdef array[double] arr = clone(array('d'), L, False)


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    # Prevents dead-code elimination

    str(d)


@timefunc("cpython.array memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr = clone(array('d'), L, False)


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    # Prevents dead-code elimination

    str(d)


@timefunc("cpython.array raw C type")

def _(int L):

    cdef int i

    cdef array arr = clone(array('d'), L, False)


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    # Prevents dead-code elimination

    str(d)


@timefunc("numpy.empty_like memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr = numpy.empty((L,), dtype='double')


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    # Prevents dead-code elimination

    str(d)


@timefunc("malloc")

def _(int L):

    cdef int i

    cdef double* arrptr = <double*> malloc(sizeof(double) * L)


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arrptr[i]


    free(arrptr)


    # Prevents dead-code elimination

    str(d)


@timefunc("malloc memoryview")

def _(int L):

    cdef int i

    cdef double* arrptr = <double*> malloc(sizeof(double) * L)

    cdef double[::1] arr = <double[:L]>arrptr


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    free(arrptr)


    # Prevents dead-code elimination

    str(d)


@timefunc("cvarray memoryview")

def _(int L):

    cdef int i

    cdef double[::1] arr = cvarray((L,),sizeof(double),'d')


    cdef double d

    for i in range(loops):

        for i in range(L):

            d = arr[i]


    # Prevents dead-code elimination

    str(d)

輸出:


INITIALISATIONS

Running cpython.array buffer

0.100040 0.097140 0.133110 0.121820 0.131630 0.108420 0.112160 μs

Running cpython.array memoryview

0.339480 0.333240 0.378790 0.445720 0.449800 0.414280 0.414060 μs

Running cpython.array raw C type

0.048270 0.049250 0.069770 0.074140 0.076300 0.060980 0.060270 μs

Running numpy.empty_like memoryview

1.006200 1.012160 1.128540 1.212350 1.250270 1.235710 1.241050 μs

Running malloc

0.021850 0.022430 0.037240 0.046260 0.039570 0.043690 0.030720 μs

Running malloc memoryview

1.640200 1.648000 1.681310 1.769610 1.755540 1.804950 1.758150 μs

Running cvarray memoryview

1.332330 1.353910 1.358160 1.481150 1.517690 1.485600 1.490790 μs


ITERATING

Running cpython.array buffer

0.010000 0.027000 0.091000 0.669000 6.314000 64.389000 635.171000 μs

Running cpython.array memoryview

0.013000 0.015000 0.058000 0.354000 3.186000 33.062000 338.300000 μs

Running cpython.array raw C type

0.014000 0.146000 0.979000 9.501000 94.160000 916.073000 9287.079000 μs

Running numpy.empty_like memoryview

0.042000 0.020000 0.057000 0.352000 3.193000 34.474000 333.089000 μs

Running malloc

0.002000 0.004000 0.064000 0.367000 3.599000 32.712000 323.858000 μs

Running malloc memoryview

0.019000 0.032000 0.070000 0.356000 3.194000 32.100000 327.929000 μs

Running cvarray memoryview

0.014000 0.026000 0.063000 0.351000 3.209000 32.013000 327.890000 μs

(之所以使用“迭代”基準,是因為某些方法在這方面具有令人驚訝的不同特征。)


按照初始化速度的順序:


malloc:這是一個嚴酷的世界,但是很快。如果您需要分配很多東西并且具有不受阻礙的迭代和索引性能,那就必須如此。但通常情況下,您是個不錯的選擇。


cpython.array raw C type:該死,很快。而且很安全。不幸的是,它通過Python來訪問其數據字段。您可以使用一個絕妙的技巧來避免這種情況:


arr.data.as_doubles[i]

在確保安全的同時,使其達到標準速度!這使它成為的絕妙替代品malloc,基本上是一個參考計數很高的版本!


cpython.array buffer:只需3到4倍的設置時間即可進入malloc,這看起來是個不錯的選擇。不幸的是,它具有大量的開銷(盡管與boundscheckand wraparound指令相比很?。?。這意味著它只能與完全安全的變體競爭,但它是初始化速度最快的變體。你的選擇。


cpython.array memoryview:這比malloc初始化要慢一個數量級。太可惜了,但是迭代的速度一樣快。這是我建議的標準解決方案,除非boundscheck或wraparound啟用(在這種情況下cpython.array buffer可能是更引人注目的折衷方案)。


其余的部分。numpy由于對象具有許多有趣的方法,因此唯一有價值的東西是。就是這樣。


查看完整回答
反對 回復 2019-12-12
?
慕容3067478

TA貢獻1773條經驗 獲得超3個贊

作為Veedrac答案的后續行動:請注意,使用python 2.7 的memoryview支持cpython.array似乎導致當前內存泄漏。這似乎是一個長期存在的問題,因為它是在用Cython用戶郵件列表中提到這里從2012年11月后運行Veedrac與用Cython版本0.22的基準通貨與兩個的Python 2.7.6和Python 2.7.9通向cpython.array使用buffer或memoryview接口初始化a時,大內存泄漏。使用Python 3.4運行腳本時,不會發生內存泄漏。我已經將此問題報告給Cython開發人員郵件列表。


查看完整回答
反對 回復 2019-12-12
  • 2 回答
  • 0 關注
  • 485 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號