ValentinBELYN / icmplib

Easily forge ICMP packets and make your own ping and traceroute.
GNU Lesser General Public License v3.0
266 stars 46 forks source link

I don't have a problem, but I want to ask something #59

Closed nudred closed 1 year ago

nudred commented 1 year ago

I really liked your module and decided to find the most performance code for myself. I wrote the following code:

from icmplib import ping, multiping
from threading import Thread
from datetime import datetime

def tr_ping():
    def p():
        r = ping('1.1.1.1', count=1, privileged=False)
    for _ in range(10000):
        tr = Thread(target=p)
        tr.start()

def as_ping():
    r = multiping(
        ['1.1.1.1' for _ in range(10000)],
        count=1,
        privileged=False
    )

def mix_ping():
    def p():
        r = multiping(
            ['1.1.1.1' for _ in range(100)],
            count=1,
            privileged=False
        )
    for _ in range(100):
        tr = Thread(target=p)
        tr.start()

start_time = datetime.now()
tr_ping()
print('Threads', datetime.now() - start_time)

start_time = datetime.now()
as_ping()
print('Async', datetime.now() - start_time)

start_time = datetime.now()
mix_ping()
print('Mix', datetime.now() - start_time)

And got the following results:

Threads 0:00:07.276730
Async 0:00:19.946009
Mix 0:00:01.290898

The results are amazing. But since I'm not very experienced, I'd like to know how bad it is to use Threading? What problems can I face if I use it?

I will be very grateful for the answer

ValentinBELYN commented 1 year ago

Hi @TylerIO,

There's nothing wrong with using threads to parallelize your code. icmplib also used them in versions lower than v3 before replacing them with asyncio more suitable for network operations of this nature.

Performance wise you should have something similar be it with asyncio. The differences you get are due to the fact that you are creating 10000 concurrent threads while the multiping function limits concurrent operations to 50 by default (concurrent_tasks parameter) to limit CPU usage.

Try these parameters instead (you may be limited by your CPU):

multiping(['1.1.1.1'] * 10000, count=1, concurrent_tasks=10000, privileged=False) # 10000 concurrent tasks
multiping(['1.1.1.1'] * 10000, count=1, concurrent_tasks=float('inf'), privileged=False) # infinite number of concurrent tasks

If you want to learn more about asyncio, I recommend you to read this article: https://realpython.com/async-io-python/ If you're not comfortable with them or you don't want to use the multiping function, threads may do the job just fine!

I hope I was able to help you.

nudred commented 1 year ago

Thanks a lot for the answer. Once again, I repeat. Your module is amazing