#๐ How can I improve this?
216 messages ยท Page 1 of 1 (latest)
@rancid tulip
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
your annotations are wrong here
https://paste.pythondiscord.com/ZK2A#1L16-L29
(presumably they are wrong elsewhere as well)
was also going to mention those shouldn't be async
I actually did consider removing the async from those.
Also removed the unused imports (aiohttp and time)
are you familiar with async?
I don't know a great deal, i was mostly forced to use it due to discord bots.
It's basically a function that runs and when it has to wait for something it frees up the process for something else to run
You can run them concurrently if you want, however I don't in this code
You asked how I can speed up the code. Running the code concurrently could be your answer.
Your database methods appear to be async, as well.
What kind of database is this running?
That is one option. But I was more concerned with the process of everything. Running it concurrently might not necessarily speed it up if the process is what is slowing it down.
!paste
Ah, sqlite.
I have to use ASYNC as this will be part of a discord bot eventually.
Reading from a file is an io bound task and async is meant for io bound tasks.
Well, no. Discord bot's methods are async, yours don't need to be for that reason.
could you take a profile of your code? there's a lot of it, so it's hard to know what the slow part is a priori. what operating system are you on?
But it's generally recommended things be async wherever necessary to avoid blocking code.
I can upload my code to github if you want. I am running on windows 10
That would generally be sound advice, if it's shown that the awaitd calls actually wait.
If they run CPU bound, they likely never give up control.
True. Thing is you aren't utilizing the full potential of async code.
instead, could you add some timers to your code to narrow down what the slow part is? it would look something like this ```py
top of file
import time
allusers_start = time.time()
allusers = await database.get_all_users()
print('allusers took', time.time() - allusers_start)
Well, one concern I see would just be here:
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
print("Getting player IDS!")
for line in file:
await player_ids(line)
allusers = await database.get_all_users()
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
print("Getting events!")
for line in file:
next_line = next(file, None) # Read the next line
You say these files could be 1million lines long. So you run through them twice.
And the second pass through you're skipping each other line. ๐ค
The slow part is when it processes the events XD
i'd mostly do that to the chunks of your main() function
you mean the for loop that calls await player_ids(line)?
Because when I put it all in 1 loop, i get issues.
and the 2nd loop I am making sure the "next line" has the required text otherwise it's not worth looking at.
I could try and put them back onto 1 loop. That would definitely speed it up.
Your first one gathers player IDs, but is it possible to work through the events without needing them all?
A single pass would be more efficient, yeah
I'll give this a shot now
what part of the program is slow, though?
I don't know the specific part. I'd have to do that timing thing suggested earlier to know specifically. But if I were to hazard a guess I'd say it's the part that checks for events lol
definitely measure before optimizing!
once you know what part in main is slow, you can continue down into the leaf functions
it's very possible something like database.get_user_by_name could be the slow part, if there's no index on the column and you have a lot of users
but there's also a bunch of other parts that could be slow, so it's hard to say what's actually going wrong
if i had to guess though, you're probably db bound
Uhh, there's only 80 users. I doubt that's slowing it down
I'm honestly thinking it could just be the sheer size of the file tbh
no, that size of file shouldn't take that long to process. you should measure your code to see where it's slow
could you share your log file
that does make it less likely, but you sort of have an N+1 problem, so the overhead of talking to the database may cause your slowdown
I can't coz the the smallest file I have is 30mb big lol
could you share it using google drive/dropbox/github
Nothing was a second or longer to process
I can upload to git? ๐ค gimme a second to scrub any passwords then
you mean no individual function call in your main took more than 1s? that would make sense. what part of main did it take the most time executing?
i'll have to print out every event if I want to know exactly which ones took the longest.
ah, you don't want to do it like that
nope lol
put the timers outside the for loops
how much time does it take to Getting player IDS! vs Getting events!
i got this at the end of every function:
if (time.time() - start) >= 1:
print(f"Wound event took: {time.time() - start}")
and this is my main:
#This is just to test.
async def main():
start = time.time()
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
print("Getting player IDS!")
for line in file:
await player_ids(line)
next_line = next(file, None) # Read the next line
if "revived" in line:
await revive_event(line=line)
elif next_line and "Die()" in next_line:
await kill_event(line=line)
elif next_line and "Wound()" in next_line:
await wound_event(line=line)
elif next_line and "suicide" in next_line:
await suicide_event(line=line)
print(f"Main took: {time.time() - start} seconds!")
try something like this ```py
async def main():
player_ids_start = time.time()
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
print("Getting player IDS!")
for line in file:
await player_ids(line)
print('player ids took', time.time() - player_ids_start)
allusers_start = time.time()
allusers = await database.get_all_users()
print('allusers took', time.time() - allusers_start)
events_start = time.time()
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
print("Getting events!")
for line in file:
next_line = next(file, None) # Read the next line
if "revived" in line:
await revive_event(line=line, allusers=allusers)
elif next_line and "Die()" in next_line:
await kill_event(line=line, allusers=allusers)
elif next_line and "Wound()" in next_line:
await wound_event(line=line, allusers=allusers)
elif next_line and "suicide" in next_line:
await suicide_event(line=line, allusers=allusers)
print('events took', time.time() - events_start)
you want to start at the root of your tree, and then work your way into the leaf functions
how long does each section take
Updated the repo to include log file
and then when you're in your leaf functions, instead of having a print you would have a global value that you add to
perhaps i'm missing something, but on my machine your code executes in 1 second
did the database populate properly?
you should have 2 tables in the database 1 events and 1 users, and a shitload of events
should i start with an empty database
Na.
ah, after running i have this
So you telling me my pc is just shit?
:( you be nice
this is 1 log file out of like 15 lol
what are the specs of your machine?
good question. Whats the command I run again?
oh
i cant send that
lemme take a screencap lol
just search "view ram info" in the search bar maybe
that's not bad at all
and you're running python test4.py to run your code?
yes
hmmmm
can you run your main function with the entire if "revived" in line: block commented out
like all of the if statements
how long does that take
then can you add back the if statements 1 by 1
and say how long it takes after adding each one back
first thought is maybe sqlite is slower on windows or something
but that seems unlikely. and definitely not 35x slower
This is when I added them 1 at a time. so the first is none, then "if revived" then added die then added wound and then finally added suicide
wow!
ok can we drill down on the revive_event case
yeah that's the case on my machine too
removed just wound and it suddenly went faster lol
though it only takes .5s longer when i enable wound
could you comment out all the if stmts except for if "revived" in line?
on my machine to run that it takes 0.11s
but on yours it looks like 3 seconds
so we want to bisect the revive_event function
Just the revive revent
then how long does it take if you comment out this section in the revive_event function
Maybe I don't commit after each entry then?
It'd probably be both.
The my code is committing to the database after each entry.
So it's probably waiting for that to commit first.
could you try measuring it?
I'll change my code now to store everything in memory and then process it all into the database at the same time.
make it 1 commit instead of thousands
but yeah, that was going to be my suggestion from up above
very common problem with dbs
but i'm curious if it's one or the other, or both that are making it slow
Wouldnt be an issue if I could use motor instead of aiosqlite lol
update vs insert
It's the insert.
what do these 4 runs represent
Order:
add_event
first update user
second update user
both update users
It's definitely anything to do with modifying the database
I'll just store everything into a dictionary and send them to the database at the end.
inside of add_event, how long does it take if you remove the commit at the end of the function?
(since the context manager should handle that for you)
Without the commit it wont save to the database. but I'll do that anyway
the context manager handles that, no? but i don't think that's the slow thing just curious
Without the commit, but it didnt save to the database
It's fine. I'll modify my code now. Gimme 10
We've identified where it's going slow
similar issue described here, https://stackoverflow.com/questions/72514674/why-sqlite-queries-run-slower-in-windows-server-machine-compared-to-ubuntu-m, which is probably the same one you have, given that aiosqlite seems to be optimizing for a multithreaded use case (https://github.com/omnilib/aiosqlite/issues/97#issuecomment-748520700)
btw are you still doing multiple inserts just not starting a transaction for each one, or are you doing one singular insert
12s is stil very surprising!
The 12s actually comes from the fact that I have to query steam sometimes
ah
async def store_events(self, events) -> None:
# Define the SQL query with placeholders
query = '''
INSERT INTO events (playerone_steamid, playertwo_steamid, kill, revive, wound, suicide, date)
VALUES (:playerone_steamid, :playertwo_steamid, :kill, :revive, :wound, :suicide, :date)
'''
# Define the dictionary of values for placeholders
async with aiosqlite.connect(self.config['database']['test_location']) as db:
# Execute the SQL query with the dictionary of values
#print(f"Events before storage: {events}\n\n")
for event in events:
#print(f"\n\nevent: {event}\n\n")
await db.execute(query, event)
await db.commit()
ah yeah you could do this with a single insert and no for loop
idk how lol
hmm actually not sure how to do it with aiosqlite
no docs online lol
and i guess your perf is fine enough now
but should definitely be able to do this almost instantly
does this next_line = next(file, None) # Read the next line actually skip a line? so im only processing half the file? or does it keep the current place in the loop and pull the next one for checking?
yeah it skips a line
AAHHH
I cant have it skipping a line on me lol
but i remember making note of that
Processing only half the file is not ideal
i just assumed that's how the log format looked
especially since some events happen back to back lol
so i guess you're back to 25s
So how can I check the next line without actually skipping a line?
turn it into a list and then check using indices
The entire file?!
it's already in memory
and even 100mb is actually not that big of a file, i promise!
if your concern is looping over it
if you really care then you can use a peekable iterator, but that's more work than necessary imo
because you're not bound by this in terms of perf
So is there a fancy way to convert it to a list or do I have to first loop through each line and append them to a list and then loop again?
list(lines)
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
file_list = list(file)
```?
that should work, yeah
#This is just to test.
async def main():
start = time.time()
events = []
with open('./testfiles/log1.log', 'r', encoding='UTF-8') as file:
file_list = list(file)
count = 0
for line in file_list:
await player_ids(line)
try:
next_line = file_list[count] # Read the next line
except:
next_line = None
if "revived" in line:
event = await revive_event(line=line)
if event:
events.append(event)
elif next_line and "Die()" in next_line:
event = await kill_event(line=line)
if event:
events.append(event)
elif next_line and "Wound()" in next_line:
event = await wound_event(line=line)
if event:
events.append(event)
elif next_line and "suicide" in next_line:
event = await suicide_event(line=line)
if event:
events.append(event)
count += 1
``` Im gonna run this anyway, but opinion?
wait
what
how the fuck
is this faster?!
looks fine to me, though i might do next_line = file_list[count] if count < len(file_list) else None instead of try/catch
that seems surprising
seems?!
it is surprising LOL
and remember that's 7 seconds mostly coz of the steam queries
could be steam just responding faster
2 without queries
And I havent fully optimized my code yet lol
This change has only been just the adding of events.
awesome!
I havent changed the update or adding user ids yet
im curious how fast it'd be on your pc now lol
Updated the repo
Fuck yeah. I love optimization when you go from like 35+ seconds to 2 seconds
now under a second on my machine
Dont spend that extra time all at once
;)
Now I got other issues lol
Explain something to me. I have changed nothing except for adding a few print lines.. and suddenly lol
nvm figured it out lol
Change one thing and shit goes to heck
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.