Apakah numpy random lebih cepat dari python random?

Suatu hari, saat bermain dengan program sederhana yang melibatkan keacakan, saya melihat sesuatu yang aneh. Python acak. fungsi randint[] terasa cukup lambat, dibandingkan dengan fungsi penghasil keacakan lainnya. Karena randint[] adalah jawaban kanonik untuk "beri saya bilangan bulat acak" dengan Python, saya memutuskan untuk menggali lebih dalam untuk memahami apa yang terjadi

Ini adalah posting singkat yang mendalami penerapan modul acak, dan membahas beberapa metode alternatif untuk menghasilkan bilangan bulat acak semu

Pertama, tolok ukur dasar [Python 3. 6]

$ python3 -m timeit -s 'import random' 'random.random[]'
10000000 loops, best of 3: 0.0523 usec per loop
$ python3 -m timeit -s 'import random' 'random.randint[0, 128]'
1000000 loops, best of 3: 1.09 usec per loop

Wah. Ini sekitar 20x lebih mahal untuk menghasilkan bilangan bulat acak dalam rentang [0, 128] daripada menghasilkan float acak dalam rentang [0, 1]. Itu cukup curam, memang

Untuk memahami mengapa randint[] sangat lambat, kita harus menggali sumber Python. Mari kita mulai dengan acak[]. Di Lib/acak. py, fungsi acak yang diekspor adalah alias dari metode acak kelas Acak, yang mewarisi metode ini langsung dari _Random. Ini adalah pendamping C yang ditentukan dalam Modules/_randommodule. c, dan ia mendefinisikan metode acaknya sebagai berikut

static PyObject *
random_random[RandomObject *self, PyObject *Py_UNUSED[ignored]]
{
    uint32_t a=genrand_int32[self]>>5, b=genrand_int32[self]>>6;
    return PyFloat_FromDouble[[a*67108864.0+b]*[1.0/9007199254740992.0]];
}
_

Di mana getrand_int32 didefinisikan langsung di atas dan mengimplementasikan langkah PRNG Mersenne Twister. Semua dalam semua, ketika kita sebut acak. random[] dengan Python, fungsi C langsung dipanggil dan tidak banyak pekerjaan tambahan yang dilakukan selain mengubah hasil genrand_int32 menjadi angka floating point di baris C

Sekarang mari kita lihat apa yang randint[] lakukan

def randint[self, a, b]:
    """Return random integer in range [a, b], including both end points.
    """

    return self.randrange[a, b+1]

Ini memanggil randrange, cukup adil. Ini dia

def randrange[self, start, stop=None, step=1, _int=int]:
    """Choose a random item from range[start, stop[, step]].

    This fixes the problem with randint[] which includes the
    endpoint; in Python this is usually not what you want.

    """

    # This code is a bit messy to make it fast for the
    # common case while still doing adequate error checking.
    istart = _int[start]
    if istart != start:
        raise ValueError["non-integer arg 1 for randrange[]"]
    if stop is None:
        if istart > 0:
            return self._randbelow[istart]
        raise ValueError["empty range for randrange[]"]

    # stop argument supplied.
    istop = _int[stop]
    if istop != stop:
        raise ValueError["non-integer stop for randrange[]"]
    width = istop - istart
    if step == 1 and width > 0:
        return istart + self._randbelow[width]
    if step == 1:
        raise ValueError["empty range for randrange[] [%d,%d, %d]" % [istart, istop, width]]

    # Non-unit step argument supplied.
    istep = _int[step]
    if istep != step:
        raise ValueError["non-integer step for randrange[]"]
    if istep > 0:
        n = [width + istep - 1] // istep
    elif istep 

Bài mới nhất

Chủ Đề