an experiment. lets don't use threading locks, hope it helps with performance

This commit is contained in:
Laura Klünder 2023-12-07 17:28:13 +01:00
parent 2e09b286f4
commit 372936fcad
8 changed files with 88 additions and 77 deletions

View file

@ -1,6 +1,5 @@
import operator
import pickle
import threading
from collections import deque
from itertools import chain
@ -17,6 +16,11 @@ from c3nav.mapdata.utils.cache import AccessRestrictionAffected, MapHistory
from c3nav.mapdata.utils.cache.package import CachePackage
from c3nav.mapdata.utils.geometry import get_rings, unwrap_geom
try:
from asgiref.local import Local as LocalContext
except ImportError:
from threading import local as LocalContext
empty_geometry_collection = GeometryCollection()
@ -292,9 +296,7 @@ class LevelRenderData:
package.save_all()
cached = {}
cache_key = None
cache_lock = threading.Lock()
cached = LocalContext()
@staticmethod
def _level_filename(pk):
@ -304,22 +306,21 @@ class LevelRenderData:
def get(cls, level):
# get the current render data from local variable if no new processed mapupdate exists.
# this is much faster than any other possible cache
with cls.cache_lock:
cache_key = MapUpdate.current_processed_cache_key()
level_pk = str(level.pk if isinstance(level, Level) else level)
if cls.cache_key != cache_key:
cls.cache_key = cache_key
cls.cached = {}
else:
result = cls.cached.get(level_pk, None)
if result is not None:
return result
cache_key = MapUpdate.current_processed_cache_key()
level_pk = str(level.pk if isinstance(level, Level) else level)
if getattr(cls.cached, 'cache_key', None) != cache_key:
cls.cached.key = cache_key
cls.cached.data = {}
else:
result = cls.cached.data.get(level_pk, None)
if result is not None:
return result
pk = level.pk if isinstance(level, Level) else level
result = pickle.load(open(cls._level_filename(pk), 'rb'))
pk = level.pk if isinstance(level, Level) else level
result = pickle.load(open(cls._level_filename(pk), 'rb'))
cls.cached[level_pk] = result
return result
cls.cached.data[level_pk] = result
return result
def save(self, pk):
return pickle.dump(self, open(self._level_filename(pk), 'wb'))

View file

@ -1,9 +1,13 @@
import math
import struct
import threading
import numpy as np
try:
from asgiref.local import Local as LocalContext
except ImportError:
from threading import local as LocalContext
class GeometryIndexed:
# binary format (everything little-endian):
@ -207,23 +211,20 @@ class LevelGeometryIndexed(GeometryIndexed):
# noinspection PyArgumentList
return self.save(self.level_filename(level_id, mode))
cached = {}
cache_key = None
cache_lock = threading.Lock()
cached = LocalContext()
@classmethod
def open_level_cached(cls, level_id, mode):
with cls.cache_lock:
from c3nav.mapdata.models import MapUpdate
cache_key = MapUpdate.current_processed_cache_key()
if cls.cache_key != cache_key:
cls.cache_key = cache_key
cls.cached = {}
else:
result = cls.cached.get((level_id, mode), None)
if result is not None:
return result
from c3nav.mapdata.models import MapUpdate
cache_key = MapUpdate.current_processed_cache_key()
if getattr(cls.cached, 'cache_key', None) != cache_key:
cls.cached.key = cache_key
cls.cached.data = {}
else:
result = cls.cached.data.get((level_id, mode), None)
if result is not None:
return result
result = cls.open_level(level_id, mode)
cls.cached[(level_id, mode)] = result
return result
result = cls.open_level(level_id, mode)
cls.cached.data[(level_id, mode)] = result
return result

View file

@ -12,6 +12,7 @@ class NoneFromCache:
class LocalCacheProxy:
# django cache, buffered using a LRU cache
# only usable for stuff that never changes, obviously
# todo: ensure thread-safety, compatible with async + daphne etc
def __init__(self, maxsize=128):
self._maxsize = maxsize
self._mapupdate = None

View file

@ -1,15 +1,19 @@
import os
import struct
import threading
from collections import namedtuple
from io import BytesIO
from tarfile import TarFile, TarInfo
from typing import BinaryIO
from typing import BinaryIO, Self
from pyzstd import CParameter, ZstdError, ZstdFile
from c3nav.mapdata.utils.cache import AccessRestrictionAffected, GeometryIndexed, MapHistory
try:
from asgiref.local import Local as LocalContext
except ImportError:
from threading import local as LocalContext
ZSTD_MAGIC_NUMBER = b"\x28\xb5\x2f\xfd"
CachePackageLevel = namedtuple('CachePackageLevel', ('history', 'restrictions'))
@ -109,23 +113,20 @@ class CachePackage:
package = settings.CACHE_ROOT / 'package.tar'
return cls.read(package.open('rb'))
cached = None
cache_key = None
cache_lock = threading.Lock()
cached = LocalContext()
@classmethod
def open_cached(cls):
with cls.cache_lock:
from c3nav.mapdata.models import MapUpdate
cache_key = MapUpdate.current_processed_cache_key()
if cls.cache_key != cache_key:
cls.cache_key = cache_key
cls.cached = None
def open_cached(cls) -> Self:
from c3nav.mapdata.models import MapUpdate
cache_key = MapUpdate.current_processed_cache_key()
if getattr(cls.cached, 'cache_key', None) != cache_key:
cls.cached.key = cache_key
cls.cached.data = None
if cls.cached is None:
cls.cached = cls.open()
if cls.cached.data is None:
cls.cached.data = cls.open()
return cls.cached
return cls.cached.data
def bounds_valid(self, minx, miny, maxx, maxy):
return (minx <= self.bounds[2] and maxx >= self.bounds[0] and