Timery Node.js są bardzo sprawnie zaimplementowane. Ich implementacja (opisana w szczegółowym artykule o tym, jak działają) może z łatwością obsłużyć bardzo dużą liczbę timerów.
Są one przechowywane na podwójnie połączonej liście, która jest posortowana i tylko z następnym uruchomionym zegarem powiązany jest rzeczywisty zegar systemu libuv. Kiedy ten zegar zostanie odpalony lub anulowany, następny na liście staje się zegarem dołączonym do rzeczywistego zegara systemu libuv. Po ustawieniu nowego timera jest on po prostu wstawiany do posortowanej listy i, o ile nie zostanie uruchomiony jako następny, po prostu siedzi na liście i czeka na swoją kolej. Możesz mieć ich tysiące bardzo wydajnie.
Oto kilka zasobów dotyczących działania tych liczników czasu:
Ile jednocześnie ustawionych limitów czasu przed problemami z wydajnością?
Jak nodejs wewnętrznie zarządza zegarami
Pierwsza referencja zawiera kilka komentarzy z rzeczywistego kodu nodejs, które opisują, jak działa system list połączonych z zegarem i do czego jest zoptymalizowany.
Drugi artykuł zawiera nieco wyższy opis tego, jak jest zorganizowany.
Istnieją inne możliwości, więc gdy jeden zegar dotrze do początku listy i zostanie uruchomiony, po wywołaniu tego wywołania zwrotnego node.js sprawdza początek listy pod kątem innych zegarów, które są teraz również gotowe do uruchomienia. Spowoduje to wyczyszczenie wszystkich innych liczników z tym samym „czasem docelowym” co pierwszy, a także wszystkich innych, które upłynął w czasie, gdy te różne inne wywołania zwrotne były uruchomione.
Kiedy masz tysiące, wstawienie nowego licznika czasu do posortowanej połączonej listy zajmie nieco więcej czasu, jeśli jest tam wiele liczników czasu, ale po wstawieniu nie ma najmniejszego znaczenia, ile jest, ponieważ zawsze patrzy tylko na następny do strzału. Tak więc proces przebywania tam z nawet dziesiątkami tysięcy oczekujących timerów to tylko jeden timer systemowy (reprezentujący następne zdarzenie timera do uruchomienia) i garść danych. Wszystkie te dane dla innych przyszłych liczników czasu nic Cię nie kosztują, samo siedzenie tam.
W przypadku JavaScript, podobnie jak w przypadku pierwszego rozwiązania pythona, mogę odrodzić tyle setTimeouts, ile potrzeba, ale problem polega na tym, że wszystkie timeouty działają w głównym wątku, ale jak powiedziałem, zadania nie wymagają dużych zasobów i potrzebuję tylko dokładności do drugi.
Wydaje mi się, że nodejs może obsłużyć twoją ilość setTimeout()
dzwoni dobrze. Gdybyś miał problem w node.js, nie byłby on spowodowany liczbą liczników czasu, ale musiałbyś mieć pewność, że używasz wystarczającej ilości procesora do rozwiązania problemu, jeśli masz więcej pracy do przetworzenia niż jeden rdzeń może obsłużyć. Możesz rozszerzyć użycie rdzenia za pomocą klastrowania nodejs lub kolejki roboczej, która używa wątków roboczych lub innych procesów nodejs, aby pomóc w przetwarzaniu. node.js jest sam w sobie bardzo wydajny we wszystkim, co jest związane z operacjami I/O, więc dopóki nie wykonujesz obliczeń intensywnie obciążających procesor, pojedynczy wątek node.js może obsłużyć wiele przetwarzania zdarzeń.
Pamiętaj, że liczniki czasu JavaScript nie dają żadnych gwarancji dokładności. Jeśli zatrzymasz procesor, niektóre liczniki uruchomią się później niż zaplanowano, ponieważ nie są one wywłaszczające. Ale jeśli Twoje zadania nie obciążają procesora, możesz być w porządku.