Jak zrobić milion operacji na sekundę.

0

Czy istnieje możliwość zrobienia miliona wywołań funkcjii w ciągu sekundy w odrębnych wątkach?

0

Kiedys gdzies czytalem. Odkopalem w chwile wiec podrzucam - A million requests per second with Python

0

A co jak będzie więcej lub mniej na sekundę?
musi być koniecznie równy milion na sekundę?

0

wpisz w google: million rps

ALE to wszystko zalezy od rodzaju systemu, requestow, ich wielksoci itp.

Jak aplikacja jest stanowa to jest trudniej

0

Skąd wiadomo że chodzi o requesty a nie o wywołanie funkcji?

3

Też bym strzelał że chodzi o funkcje na podstawie: możliwość zrobienia miliona wywołań funkcjii

Anyway, wracając do pytania. Odpowiedź nie jest tak prosta i jednoznaczna jak samo pytanie :).
Lekcja historii informatyki: [konkluzja dla leniwych po przełamaniu linii]
Bierze się to choćby z tego faktu że procesor (póki co mówię o pierwotnych - nim ktoś zacznie się doszukiwać) nie jest w stanie wykonywać kilku zadań jednocześnie, co udowodniły nam pierwsze wersje DOS'a, kto pamięta ten wie. W kolejnych odsłonach pojawiło się coś takiego jak 'przełączanie zadań' (jakoś się to konkretnie nazywało, ale nie pamiętam, sry). Chodziło mniej więcej o to, że procesor skoro nie może robić dwóch rzeczy na raz, to przełączał się pomiędzy operacjami na tyle szybko, że dawał złudzenie wielozadaniowości. Ponieważ maszyna ma swoje ograniczenia w pewnych zakresach (np. prędkość zapisu danych na dysku) to bezsensem było oczekiwanie na zakończenie zgrywania, skoro procesor był na tyle szybki, aby zgrywać i przełączać się na coś innego, bo szybciej się zapisywać nie dało. Obecnie do tego pojęcia doszły nam rdzenie, które tak naprawdę są 'starym pojęciem procesora'.

Konkluzja:
Czyli... Zależnie od ilości rdzeni, tyle wywołań funkcji możesz zrobić jednocześnie. (Czyli ilość rdzeni = zmienna sprzętowa)

Następny czynnik:
Procesor posiadający 1 GHz (załóżmy dla uproszczenia) że wykonuje milion operacji stałoprzecinkowych na sekundę, więc moc każdego z rdzeni również ma znaczenie.

Ostatni czynnik:
Złożoność obliczeniowa twojej funkcji. Jeśli jest to samo jej wywołanie, nie wiem ile zajmie to operacji, jednak każde działanie wymaga pewnej ilość operacji które musi wykonać procesor. Zakładając że mamy rdzeń 1 GHz w pełni poświęcony programowi, zakładając przykładowo że wywołanie funkcji to cztery operacje procesora, już mamy 250 tysięcy wywołań na sekundę.

Finał:
Wszystko zależy od twojego sprzętu. Niestety nie wczytywałem się w bibliotekę Wątków czy one mogą być przypisane do różnych rdzeni. Ale zakładając że tak... To w zależności od złożoności funkcji, możesz być w stanie wywołać ją milion razy.
Dorzucam programik którym sobie możesz to sprawdzić [obarczony błędem dodatkowej/ych operacji na sprawdzenie pętli]

from time import time

def twoja_funkcja(*args, **kwargs):
    pass

def main(func):
    start = time()+1
    licznik = 0
    #Tutaj możesz sobie też wystartować wątki i w poszczególnych wątkach uruchomić tę samą funkcję wielokrotnie i zobaczyć jak będzie program przyspieszał.
    while time() < start:
        func()
        licznik += 1
    print("Ilość wywołań:", licznik)

if __name__ == "__main__":
     main(twoja_funkcja)

Przykład wyniku u mnie:
>>> main(twoja_funkcja)
Ilość wywołań: 3 582 518
Dodałem spację dla czytelności. Procek dał radę wywołać funkcję pomimo dodatkowych operacji dodawania, przypisania i porównywania 3 i pół miliona razy. I to bez dzielenia na wątki. Oczywiście ile wątków jest uruchomionych jednocześnie, tyle razy licznik trzeba zwiększyć.

from threading import Thread
from time import time

class counter(Thread):
    def __init__(self):
        Thread.__init__(self)
        print("Wystartowałem!")
        self.wartosc = 0
        self.start()

    def run(self):
        while True:
            self.wartosc += 1

def main():
    start = time()+1
    licznik = counter()
    licznik2 = counter()
    while time() < start:
        pass
    print("Ilość wywołań:", licznik.wartosc+licznik2.wartosc)
    print("Ilość wywołań:", licznik.wartosc, "|", licznik2.wartosc)
    exit()

if __name__ == "__main__":
     main()

Tu już się robi ciekawiej:
Ilość wywołań: 9739770 Ilość wywołań: 4903460 | 4897741 prawie 10 milionów.

Co pozwala wysunąć wniosek, że nawet wystartowanie jednego wątku przyspiesza niewiarygodnie wywołanie funkcji... Sprawdźmy gdy ruszymy tylko jeden. (Teraz to już jest zabawa również dla mnie :D )

from threading import Thread
from time import time

class counter(Thread):
    def __init__(self):
        Thread.__init__(self)
        print("Wystartowałem!")
        self.wartosc = 0
        self.start()

    def run(self):
        while True:
            self.wartosc += 1

def main():
    start = time()+1
    licznik = counter()
    while time() < start:
        pass
    print("Ilość wywołań:", licznik.wartosc)
    exit()

if __name__ == "__main__":
     main()

Ilość wywołań: 6 152 653 6 milionów
Ciekawe o ile skalę zaburzył fakt że tutaj jest wykonywane jedno dodawanie, a tam były dwa, czy stąd ta różnica ponad dwóch milionów operacji na wątek... To już musisz sprawdzić samemu :)

Zaznaczę że mój sprzęt jest stosunkowo wolny, uruchamiałem bez Jit'a i innych 'przyspieszaczy' więc zachęcam do testowania samemu, ja testy uruchamiałem po razie, więc możesz sobie uruchomić np. na 0.01 sekundy. Zebrać dane np. z tysiąca pomiarów i wyciągnąć średnią arytmetyczną i medianę. Miłej zabawy :D

No i pamiętaj, tu funkcja zasadniczo nic nie robi, większa złożoność obliczeniowa = mniej wywołań na sekundę. Gdy potrzebujesz taki ogrom wywołań, to polecam dobrze się przygotować z optymalizacji prędkości wykonywania kodu.

0

Dzięki wszystkim. Chodzi faktycznie o requesty.

0

chodzi co o ddos ?

0

Nie. Muszę przeskanować miliony ip. Strasznie długo to trwa.

1
xenix33 napisał(a):

Nie. Muszę przeskanować miliony ip. Strasznie długo to trwa.

Skoro tak, to wąskim gardłem jest sieć, a nie CPU.

-- edited:
Załóżmy, że wszystkie IP odpowiadają na pinga w 10ms. Masz 10 ms * 1 milion = 0.01 * 1000000 = 10 000 --> potrzebujesz tak ze 3h jak będziesz to wykonywał szeregowo (na jednym wątku). Możesz sobie uruchomić np. 20 procesów (każdy przetwarza po 50k IPków) i masz tylko 500 sekund ...

Dodatkowo, jak pakiet pinga ma 32 bajty (windows), to potrzebujesz wysłać (i odebrać ) 32 000 000 bajtów (czyli 30.5 MB) - 30.5 * 8 = 244 Mbity (ale nie wysycisz łącza w 100%, więc potrzebujesz na oko ze 300MBit), albo więcej cierpliwości ;-)

1

@Guaz: z tymi wątkami w Pythonie może być różnie... https://wiki.python.org/moin/GlobalInterpreterLock
Zamiast wątków można by spróbować użyć procesów ;) https://docs.python.org/3/library/multiprocessing.html

0

A funkcje asynchroniczne?

1

Problem to nie python tylko twoja karta sieciowa. Po prostu nie wyrobisz sie sieciowo i tyle. Musiałbyś to rozproszyć na wiecej maszyn które wysyłają requesty.

1

GIL jest problemem tylko przy kodzie, który jest ograniczony przez CPU.
Jeśli ograniczeniem jest I/O to GIL raczej nie będzie problemem.
Inna kwestia, że Python do najszybszych nie należy, więc YMMV.

0

az napisał(a)](https://4programmers.net/Forum/1530465):

Następny czynnik:
Procesor posiadający 1 GHz wykonuje milion operacji stałoprzecinkowych na sekundę, więc moc każdego z rdzeni również ma znaczenie.

Co to za dane nie wiadomo skąd?
Częstotliwość pracy procesora nie określa liczby wykonywanych instrukcji w jednostce czasu.

Procesor ma raczej parametr: liczba instrukcji wykonywanych podczas jednego cyklu zegara, który niekoniecznie musi być większy od 1, ale może.

0

Co włamujesz się nie kamerki lub inne publicznie niezabezpieczone dane?

1 użytkowników online, w tym zalogowanych: 0, gości: 1