@yraiv

Как считать время у большого количества объектов?

Игра симулятор мусорщика, так получается, что игрок в определенные моменты, которые очень часто бывают, видит перед собой очень большое количество различных продуктов. И суть в том, что продукты должны иметь срок годности и менять свой внешний вид(модельку) в зависимости от того какой срок годности у них сейчас остался. Объектов может быть в одном месте много, срок годности задаётся у них рандомно, но в некотором диапазоне, есть время, через которые 1 модель должна смениться на другую, но не понимаю, как реализовать подсчет этого времени. Тип, если делать таймер на каждый объект, то это же ужас будет, а если делать 1 общий таймер и через подписки и тд работать, то тоже же память кушает, когда у меня очень много объектов, как быть?
  • Вопрос задан
  • 163 просмотра
Решения вопроса 2
AshBlade
@AshBlade Куратор тега C#
Просто хочу быть счастливым
Пусть у каждого объекта будет свой штамп времени - когда он протухает.
В Update() проверяешь текущее время и время протухания - если превышено (и при этом предыдущее состояние не протухло), то меняешь вид/представление.
Этакая машина состояний

P.S. я не unity разраб., возможно во фреймворке уже есть готовые решения для такого
Ответ написан
AleksejMsk
@AleksejMsk
Программирую от души за деньги
У меня есть готовая реализации (thread safe) когда надо найти объекты с временем жизни среди миллионов с минимальным расходованием CPU.
Nuget https://www.nuget.org/packages/ShtrihM.Wattle3.Con...

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using ShtrihM.Wattle3.Containers.DateTimeCollections;
using ShtrihM.Wattle3.DomainObjects;
using ShtrihM.Wattle3.DomainObjects.Common;

namespace ShtrihM.Wattle3.Tests.DomainObjects.TestsContainers;

[TestFixture]
public class TestsDateTimeEntries
{
    public class DateTimeEntry : IDateTimeEntry
    {
        public static long CountCanTake;

        public DateTimeEntry(DateTime point, long identity)
        {
            Point = point;
            Identity = identity;
        }

        public bool CanTake(DateTime takePoint)
        {
            Interlocked.Increment(ref CountCanTake);

            var result = Point <= takePoint;

            return result;
        }

        public DateTime Point { get; }
        public long Identity { get; }
    }

    [Test]
    [TestCase(1_000_000, 1)]
    [TestCase(1_000_000, 2)]
    [TestCase(1_000_000, 1_0)]
    [TestCase(1_000_000, 1_00)]
    [TestCase(1_000_000, 1_000)]
    [TestCase(1_000_000, 1_00_000)]
    public void Test_Metrics(int size, int factor)
    {
        var instance =
            new DateTimeEntries<DateTimeEntry>(
                new LocksPoolAsync<long>(
                    Guid.NewGuid(),
                    "Test",
                    "Test",
                    new TimeService()));
        var entries = new ConcurrentDictionary<long, DateTimeEntry>(Environment.ProcessorCount, size);
        var startPoint = new DateTime(2023, 5, 5, 5, 5, 5);
        Parallel.For(0, size,
            i =>
            {
                var point = startPoint.AddMinutes(i);
                var temp = new DateTimeEntry(point, i);
                Assert.IsTrue(instance.TryAdd(point, temp));
                Assert.IsTrue(entries.TryAdd(temp.Identity, temp));
            });

        // ReSharper disable once PossibleLossOfFraction
        var point = startPoint.AddMinutes(size / factor - 1);

        Console.WriteLine($"Элементов : {size}");
        Console.WriteLine($"Выбор первых : {size / factor}");
        Console.WriteLine();
        Console.WriteLine("DateTimeEntries :");
        var sw = Stopwatch.StartNew();
        DateTimeEntry.CountCanTake = 0;
        var items = instance.Take(point, false);
        sw.Stop();
        Assert.AreEqual(size / factor, items.Count);
        Console.WriteLine($"Count = {items.Count}");
        Console.WriteLine($"Time = {sw.Elapsed}");
        Console.WriteLine($"CanTake = {DateTimeEntry.CountCanTake}");

        Console.WriteLine();
        Console.WriteLine("ConcurrentDictionary + Parallel.ForEach :");
        sw = Stopwatch.StartNew();
        DateTimeEntry.CountCanTake = 0;
        items = new List<DateTimeEntry>(size);
        Parallel.ForEach(entries,
            @entry =>
            {
                if (false == @entry.Value.CanTake(point))
                {
                    return;
                }

                lock (items)
                {
                    items.Add(@entry.Value);
                }
            });
        sw.Stop();
        Assert.AreEqual(size / factor, items.Count);
        Console.WriteLine($"Count = {items.Count}");
        Console.WriteLine($"Time = {sw.Elapsed}");
        Console.WriteLine($"CanTake = {DateTimeEntry.CountCanTake}");
    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы