Files
2026-07-13 13:35:51 +08:00

94 lines
2.5 KiB
Python

"""Base classes and functionalities for feature storages."""
import threading
STORAGE_WRAPPERS = {}
def register_storage_wrapper(type_):
"""Decorator that associates a type to a ``FeatureStorage`` object."""
def deco(cls):
STORAGE_WRAPPERS[type_] = cls
return cls
return deco
def wrap_storage(storage):
"""Wrap an object into a FeatureStorage as specified by the ``register_storage_wrapper``
decorators.
"""
for type_, storage_cls in STORAGE_WRAPPERS.items():
if isinstance(storage, type_):
return storage_cls(storage)
assert isinstance(
storage, FeatureStorage
), "The frame column must be a tensor or a FeatureStorage object, got {}".format(
type(storage)
)
return storage
class _FuncWrapper(object):
def __init__(self, func):
self.func = func
def __call__(self, buf, *args):
buf[0] = self.func(*args)
class ThreadedFuture(object):
"""Wraps a function into a future asynchronously executed by a Python
``threading.Thread`. The function is being executed upon instantiation of
this object.
"""
def __init__(self, target, args):
self.buf = [None]
thread = threading.Thread(
target=_FuncWrapper(target),
args=[self.buf] + list(args),
daemon=True,
)
thread.start()
self.thread = thread
def wait(self):
"""Blocks the current thread until the result becomes available and returns it."""
self.thread.join()
return self.buf[0]
class FeatureStorage(object):
"""Feature storage object which should support a fetch() operation. It is the
counterpart of a tensor for homogeneous graphs, or a dict of tensor for heterogeneous
graphs where the keys are node/edge types.
"""
def requires_ddp(self):
"""Whether the FeatureStorage requires the DataLoader to set use_ddp."""
return False
def fetch(self, indices, device, pin_memory=False, **kwargs):
"""Retrieve the features at the given indices.
If :attr:`indices` is a tensor, this is equivalent to
.. code::
storage[indices]
If :attr:`indices` is a dict of tensor, this is equivalent to
.. code::
{k: storage[k][indices[k]] for k in indices.keys()}
The subclasses can choose to utilize or ignore the flag :attr:`pin_memory`
depending on the underlying framework.
"""
raise NotImplementedError