Constructing typed List slow

Numba 0.55.1, python 3.7.1, Windows 10
This has been mentioned other places but I don’t feel like I’ve seen any resolution… in the example below, merely creating an empty list takes more than a tenth of a second, and the total of creating the list and adding two elements is more than four tenths of a second. In my experience the timings are slightly different on linux, but still way more than I’d expect.

I’m aware of @DannyWeitekamp’s work getting pointers to the functions as integers but hoped that this simpler solution might be a bit more performant.

Is there any solution? Or hope for improvement here? Typical output and program are below

making an empty list takes 0.124 seconds
making and populating typed list took 0.417 second for 2 items

import numba
import time

@numba.njit
def my_sum(a, b):
    return a + b

@numba.njit
def my_subtract(a, b):
    return a - b

def make_typed_list(pylist):
    lst_type = pylist[0].nopython_signatures[0].as_type()
    start = time.time()
    lst = numba.typed.List.empty_list(lst_type)
    print(f'making an empty list takes {time.time() - start:.3f} seconds')
    [lst.append(x) for x in pylist]
    return lst

my_sum(3, 4)
my_subtract(3, 4)

start = time.time()
py_list = [my_sum, my_subtract]
lst = make_typed_list(py_list)
print(f'making and populating typed list took {time.time() - start:.3f} second for {len(py_list)} items')

@numba.njit
def do_all(fns, a, b):
    for fn in fns:
        print(fn(a, b))

do_all(lst, 3, 7)

If you run your test a second time in the same session (or same ipython notebook) the second time will execute significantly faster since the overloads for instantiating a list for and appending FunctionType(f8(f8,f8)) will already be compiled. Although if you have to build a lot of lists on the python side, and they consist of many different types then your startup time can definitely bloat a lot since numba needs to compile the constructor and append methods for every new type. Numba doesn’t cache the internal methods for List, and Dict by default but you can force it to cache these methods with a monkey-patch. The following should work:

from numba.core.dispatcher import Dispatcher
import numba.typed.typedlist as tl_mod 
import numba.typed.typeddict as td_mod
#Monkey Patch Numba so that the builtin functions for List() and Dict() cache between runs 
def monkey_patch_caching(mod,exclude=[]):
    for name, val in mod.__dict__.items():
        if(isinstance(val,Dispatcher) and name not in exclude):
            val.enable_caching()

monkey_patch_caching(tl_mod,['_sort'])
monkey_patch_caching(td_mod)

Note that this monkey-patching method opens you up to an annoying bug if you happen to use a lot of custom types.

Thanks, that’s helpful. I need to dig into it a little more; I had thought that the list types should be more similar than they appear to be. Right now I’m spending about 25% of my 90-second runtime creating these lists.
Also thanks for the monkey-patch. It does scare me a little though I occasionally have resorted to such skullduggery myself. :slight_smile: