W zależności od wpisywaćstruktury danych, MemoryStoreService narzuca ograniczenia na pamięć i liczbę przedmiotów w strukturze danych.Wszystkie struktury danych są również ograniczone przez globalny limit żądań na poziomie rozdziału.
Każde doświadczenie Roblox ma Panel obserwacji przechowywania pamięci, który zawiera zestaw wykresów, których możesz używać do monitorowania zużycia przechowywania pamięci.
Sortowane mapy i kolejki
Sortowane mapy i kolejki obie mają ograniczenia dotyczące maksymalnej liczby przedmiotów i maksymalnej pamięci.Ponadto elementy w jednej z tych struktur danych zawsze znajdują się na jednej partycji.Każde żądanie do jednej z tych struktur danych jest żądaniem do tej samej partycji.
Gdy sortowana mapa lub kolejki osiągnie swój limit przedmiotów lub pamięci, najlepszym rozwiązaniem jest usunięcie niepotrzebnych przedmiotów ręcznie lub poprzez dodanie polityki wygasania dla przedmiotów.Alternatywnie, jeśli tylko ograniczenie pamięci powoduje spowolnienie, możesz spróbować zmniejszyć rozmiar swoich przedmiotów poprzez usunięcie niepotrzebnych informacji z kluczy i wartości.
Jeśli potrzebujesz wszystkich swoich przedmiotów lub doświadczasz spowolnienia z powodu przepustowości żądań, jedynym rozwiązaniem jest rozdzielanie.
Rozdzielanie
Rozdzielanie to proces przechowywania zestawu powiązanych danych na kilku strukturach danych.Innymi słowy, oznacza to wzięcie istniejącej, wysokowydajnej struktury danych i zastąpienie jej wieloma, mniejszymi strukturami, które razem zawierają ten sam zestaw danych, co oryginał.
Głównym wyzwaniem przy rozdzielaniu jest znalezienie sposobu rozprzestrzeniania danych na wiele struktur danych w taki sposób, który zachowuje taką samą funkcjonalność jak oryginał.
Rozdzielanie sortowanej mapy
Aby rozdzielić sortowaną mapę, rozważ podzielenie danych na alfabetyczne podsekcje z przedziałami znaków.Na przykład, załóż, że masz tylko klucze z pierwszą literą od A do Z, i uważasz, że cztery sortowane mapy są wystarczające dla obecnego przypadku użytkowania i przyszłego wzrostu:
- Pierwsza mapa może pokrywać A-G, druga H-N, trzecia O-T i czwarta U-Z.
- Aby wstawić lub odzyskać przedmiot, użyj odpowiedniej mapy w oparciu o początkową literę przedmiotu.
Rozdzielanie mapy sortowanej
-- Uruchom usługę MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Stwórz swoje sortowane kosze map
local sm_AtoG = MemoryStoreService:GetSortedMap("AtoG")
local sm_HtoM = MemoryStoreService:GetSortedMap("HtoM")
local sm_NtoT = MemoryStoreService:GetSortedMap("NtoT")
local sm_UtoZ = MemoryStoreService:GetSortedMap("UtoZ")
-- Funkcja pomocnicza do odzyskania poprawnego kosza z kluczem przedmiotu
local function getSortedMapBucket(itemKey)
if (itemKey >= "a" and itemKey < "h") then
return sm_AtoG
elseif (itemKey < "n") then
return sm_HtoM
elseif (itemKey < "u") then
return sm_NtoT
else
return sm_UtoZ
end
end
-- Uruchom nazwy graczy z domyślną wartością 0
for _, player in game:GetService("Players"):GetPlayers() do
local bucket = getSortedMapBucket(player)
bucket:SetAsync(player, 0, 600)
end
-- Zwróć wartość gracza
local player = "myPlayer"
local bucket = getSortedMapBucket(player)
local playerScore = bucket:GetAsync(player)
print(playerScore)
Rozdzielanie kolejki
Rozdzielanie kolejki jest trudniejsze niż rozdzielanie sortowanej mapy.Chociaż chcesz rozłożyć przepustowość żądań na wiele kolejek, dodawanie, odczytywanie i usuwanie zdarzają się tylko na froncie lub na tyłach kolejki.
Jednym rozwiązaniem jest użycie kolejki obrotowej, co oznacza utworzenie wielu kolejek i rotację między nimi, gdy dodajesz lub czytasz przedmiot:
Stwórz kilka kolejek i dodaj je do matrycy.
Stwórz dwa lokalne wskazania. Jedno reprezentuje kolejkę, z której chcesz czytać i usuwać przedmioty. Inne reprezentuje kolejkę, do której chcesz dodawać przedmioty:
- Dla operacji odczytu oblicz liczbę elementów, których potrzebujesz z każdej kolejki, a także miejsce, do którego należy przenieść wskaznik odczytu.
- Aby usunąć operacje, przekaż ID z odczytu do każdej kolejki.
- Aby dodać operacje, dodaj do kolejki w punkcie dodania i zwiększ wskaznik.
Rozdzielanie kolejki
-- Uruchom usługę MemoryStore
local MemoryStoreService = game:GetService("MemoryStoreService")
-- Stwórz swoje kolejki
local q1 = MemoryStoreService:GetQueue("q1")
local q2 = MemoryStoreService:GetQueue("q2")
local q3 = MemoryStoreService:GetQueue("q3")
local q4 = MemoryStoreService:GetQueue("q4")
-- Umieść kolejki w matrycy
local queueArr = { q1, q2, q3, q4 }
-- Utwórz dwa wskazniki reprezentujące indeksy odczytu i dodaj kolejki
local readIndex = 1
local addIndex = 1
-- Stwórz lokalną funkcję, która odpowiednio aktualizuje indeksy
local function rotateIndex(index, n)
return (index + n - 1) % 4 + 1
end
-- Stwórz lokalną funkcję, która odczytuje n przedmiotów z kolejki
local function readFromQueue(count, allOrNothing, waitTimeout)
local endIndex = count % 4
local countPerQueue = count // 4
local items = {}
local ids = {}
-- pętla przez każdą kolejkę
for i = 1, 4, 1 do
-- określ, czy ta kolejka przeczyta dodatkowy przedmiot
local diff = i - readIndex
if diff < 0 then
diff += 4
end
local queue = queueArr[i]
-- czytaj przedmioty z każdej kolejki
-- +1 przedmiotów, jeśli spełnia dodatkowe kryteria odczytu
if diff < endIndex then
items[i], ids[i] = queue:ReadAsync(countPerQueue + 1, allOrNothing,waitTimeout)
else
items[i], ids[i] = queue:ReadAsync(countPerQueue, allOrNothing,waitTimeout)
end
end
readIndex = rotateIndex(readIndex, count)
return items, ids
end
-- Stwórz lokalną funkcję, która usuwa z kolejki n przedmiotów
local function removeFromQueue(ids)
for i = 1, 4, 1 do
local queue = queueArr[readIndex]
queue:RemoveAsync(ids[i])
end
end
-- Stwórz lokalną funkcję, która dodaje przedmiot do kolejki
local function addToQueue(itemKey, expiration, priority)
local queue = queueArr[readIndex]
queue:AddAsync(itemKey, expiration, priority)
addIndex = rotateIndex(addIndex, 1)
end
-- Napisz trochę kodu!
for _, player in game:GetService("Players"):GetPlayers() do
addToQueue(player, 600, 0)
end
local players, ids = readFromQueue(20, true, -1)
removeFromQueue(ids)
Mapy haszu
Mapy haszu nie mają indywidualnych ograniczeń pamięci lub liczby przedmiotów i są automatycznie rozdzielane, ale nadal możesz napotkać lagi, jeśli używasz ich źle.
Na przykład, rozważ doświadczenie z mapą haszy danych gry przechowywaną jako wartość pojedynczego klucza o nazwie metadata.Jeśli te metadane zawierają zagnieżdżony obiekt z informacjami, takimi jak identyfikator miejsca, liczba graczy i więcej, za każdym razem, gdy potrzebne są metadane, nie masz innego wyboru, jak wezwanie GetAsync("metadata") i odzyskanie całego obiektu.W tym przypadku wszystkie żądania przechodzą do jednego klucza i zatem do jednej partycji.
Zamiast przechowywać całe metadane jako pojedynczy, zagnieżdżony obiekt, lepszym podejściem jest przechowywanie każdego pola jako własnego klucza, aby mapa haszu mogła skorzystać z automatycznego rozdzielania.Jeśli potrzebujesz oddzielenia między metadanymi a resztą mapy haszy, dodaj prefiks nazwy (np.metadata_user_count zamiast po prostu user_count ).