Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 709 710 [711] 712 713 ... 796

Author Topic: if self.isCoder(): post() #Programming Thread  (Read 890039 times)

RoguelikeRazuka

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10650 on: December 05, 2017, 06:43:56 pm »

No, unfortunately I couldn't find a solution that would suit my needs :( Had to switch to Python instead.


Here's another question. The thing is, I'm making a GUI program using Python's Tkinter. It has a button which if pressed calls a function which does some computations. The problem is that depending on the input it may take quite some time to get the result. Besides, when the function gets control the GUI of course feezes so user is unable to close the application correctly in case he got tired of waiting and he wants to stop execution immediately. I could fix the problem making the function run in an infinite loop and check some flag value on every iteration, but again performing a single iteration may take qute a long time, so I'm not sure this is a good solution for me. Another idea I've come up with is to use Python's threating.Timer class in order to run another thread (inside the function which runs in it's own thread, that is starting a thread from another thread) checking the flag value for that function, yet in this case I'd have to work out communication between the two threads which I'm not particularly experienced in, so I would be very grateful if anyone suggested me a more simple way to achieve what I just described.
« Last Edit: December 05, 2017, 06:54:53 pm by RoguelikeRazuka »
Logged

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10651 on: December 05, 2017, 07:19:42 pm »

Unfortunately, I cannot see a solution that doesn't use threading. And it's not that complicated; the most you'd need is a mutex (which is implemented as threading.Lock in Python). Basically start up a new thread which runs that function, and whenever either the function or the main code needs to interact with tkinter, it locks the mutex and then releases it after it's done. Tkinter might even be thread-safe (I'm not sure), in which case you don't even need that.

Though there might be some threadless solution I haven't seen yet, so don't give up hope if that's what you want.
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10652 on: December 05, 2017, 07:24:38 pm »

My suggestion for refactoring a monolithic function for this would be to turn it into an object, and move any local variables from the function into the object's body. Get that working as-is, then break up the original function into e.g a "init" part and a "process_chunk" part. You can control how many iterations are called per "chunk" so that it's not calling the GUI too many times during processing. Have a bool or similar in the object that records whether the processing is completed. Then you have some code that runs each frame, and it checks if the object has any unfinished processing to do, and calls the "process_chunk" function if it does.

This is probably the easiest way to do it if you're not going for multi-threading. Also the advantages of doing this "chunk" thing is that if you do go for multi-threading you can then process the chunks in multiple threads at once, rather than just doing the function in a single thread by itself. Knowing how to break big functions down into chunks is critical for getting the most out of multi-processing hardware. Of course this will depend on what your function is doing and what things can be calculated in parallel.
« Last Edit: December 05, 2017, 07:30:20 pm by Reelya »
Logged

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10653 on: December 05, 2017, 09:54:12 pm »

My suggestion for refactoring a monolithic function for this would be to turn it into an object, and move any local variables from the function into the object's body. Get that working as-is, then break up the original function into e.g a "init" part and a "process_chunk" part. You can control how many iterations are called per "chunk" so that it's not calling the GUI too many times during processing. Have a bool or similar in the object that records whether the processing is completed. Then you have some code that runs each frame, and it checks if the object has any unfinished processing to do, and calls the "process_chunk" function if it does.

This is probably the easiest way to do it if you're not going for multi-threading. Also the advantages of doing this "chunk" thing is that if you do go for multi-threading you can then process the chunks in multiple threads at once, rather than just doing the function in a single thread by itself. Knowing how to break big functions down into chunks is critical for getting the most out of multi-processing hardware. Of course this will depend on what your function is doing and what things can be calculated in parallel.

The problem isn't that the function is calling the GUI too many times; it's that it's blocking the event loop, which causes the window to freeze. Every cycle in the event loop, tkinter (or actually the tk backend) handles events, invokes callbacks, etc. and then hands control over to the operating system for a little bit. If the former takes too long, and the latter is not handled in a timely manner, the operating system thinks something is wrong (which causes the "not responding" title tag in Windows, for example.)
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10654 on: December 05, 2017, 11:56:15 pm »

And that ladies and gentlemen, is why you always run the event loop in a separate thread. Probably can't do that effectively in python though.
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10655 on: December 06, 2017, 12:10:50 am »

And that ladies and gentlemen, is why you always run the event loop in a separate thread. Probably can't do that effectively in python though.

Technically, you can, but you would have to do some wrangling to somehow make the computation function (which is invoked by the button press callback) to run in the main thread.
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10656 on: December 06, 2017, 07:14:09 am »

The problem isn't that the function is calling the GUI too many times; it's that it's blocking the event loop, which causes the window to freeze. Every cycle in the event loop, tkinter (or actually the tk backend) handles events, invokes callbacks, etc. and then hands control over to the operating system for a little bit. If the former takes too long, and the latter is not handled in a timely manner, the operating system thinks something is wrong (which causes the "not responding" title tag in Windows, for example.)

The whole point of what I was saying was that you attach your function to a callback. By breaking the processing into chunks then returning, you ensure you never run for too long. By making your processing into an object you ensure that state is saved between each call to the function. The advantage of knowing how to do this general kind of thing is that it will work with any language and framework.

Any framework will give you some sort of "hooks" (which might be called callbacks, events, update function, whatever: it doesn't matter) that run per-frame and you can attach your own code to, so that you can run your own stuff with it without needing to spawn an entire new thread for it. Just read the documentation, find out how you're expected to attach code to it that runs every frame, then make sure that your amount of processing done per call is some reasonably limited amount. Which is where using an object to store processing state is useful.

The reasons that your button-function was blocking was that your were attaching the whole load of processing to the button and not returning at intervals. e.g. in this example, what you do is attach a small function to the button instead, which sets some flags that "processing is started", then you have another function attached to whatever tkinter gives you that runs each frame, and each frame it checks whether there's any processing to do, does a bit, then returns. It'll keep running until processing is finished. Another advantage of doing this is having a real easy way to design dynamic progress bars. You can have your per-frame processing function return a value for the % of processing that's finished and then easily set some display elements to show it.
« Last Edit: December 06, 2017, 07:40:22 am by Reelya »
Logged

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10657 on: December 06, 2017, 12:10:43 pm »

Okay, I get what you're saying, but there's no way to make something run every update cycle in tkinter. You could make the function schedule itself to be run in a certain amount of time with the after() method, however.
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10658 on: December 06, 2017, 01:50:40 pm »

I find it hard to believe that if tkinter is the only GUI available for Python, as their website suggests, that they lack any standard callbacks such as a drawframe function.

As a quick guess, you're using tk.mainloop to run your tkinter stuff? You should stop doing that and use the code from one answer here instead:

https://stackoverflow.com/questions/29158220/tkinter-understanding-mainloop

Code: [Select]
while True:
    tk.update_idletasks()
    tk.update()

The problem is that tk.mainloop is a blocking function - it takes control away from you, and never gives it back. By explicitly creating your own while loop and calling tkinter's update functions yourself, then you get control back over the main loop, meaning you can add whatever you can think up to run every update cycle.
« Last Edit: December 06, 2017, 02:01:45 pm by Reelya »
Logged

bloop_bleep

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10659 on: December 06, 2017, 02:01:29 pm »

I find it hard to believe that if tkinter is the only GUI available for Python, as their website suggests, that they lack any standard callbacks such as a drawframe function.

No, it's not the only GUI, but it's the only GUI included in Python by default, which is why it's the most commonly used. Also, no, I don't think they have any support for callbacks such as that. You can use after() to schedule your task in 1 millisecond, which should probably make the function run the next cycle.
Logged
Quote from: KittyTac
The closest thing Bay12 has to a flamewar is an argument over philosophy that slowly transitioned to an argument about quantum mechanics.
Quote from: thefriendlyhacker
The trick is to only make predictions semi-seriously.  That way, I don't have a 98% failure rate. I have a 98% sarcasm rate.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10660 on: December 06, 2017, 02:02:33 pm »

what about the tk.mainloop thing? If you're using that, then use the other thing, then you can control it however you want, since if you have access to the main loop, you don't need callbacks - you just cram your own extra update functions in there too.

lethosor

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10661 on: December 06, 2017, 02:44:54 pm »

Also the advantages of doing this "chunk" thing is that if you do go for multi-threading you can then process the chunks in multiple threads at once, rather than just doing the function in a single thread by itself. Knowing how to break big functions down into chunks is critical for getting the most out of multi-processing hardware. Of course this will depend on what your function is doing and what things can be calculated in parallel.
It's worth noting that doing computationally-expensive things in multiple threads at once in Python will typically not improve performance, because of the GIL. Other than that, the "chunks" approach could work, perhaps in combination with the mainloop() replacement you gave. (Also, regarding that, using "mainloop()" isn't necessarily wrong - it's useful to replace it with something else in this case, but that doesn't make it wrong in all cases.)

And that ladies and gentlemen, is why you always run the event loop in a separate thread. Probably can't do that effectively in python though.
Well, in this case, you must run Tkinter's event loop in the main thread; otherwise, it will probably hang or crash. I believe that has to do with Tk, though, not Python.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

milo christiansen

  • Bay Watcher
  • Something generic here
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10662 on: December 06, 2017, 05:10:39 pm »

Generally what you do with GUIs and other things that need to be in the main thread is start your real work in new threads, then turn the main thread into the GUI thread.
Logged
Rubble 8 - The most powerful modding suite in existence!
After all, coke is for furnaces, not for snorting.
You're not true dwarven royalty unless you own the complete 'Signature Collection' baby-bone bedroom set from NOKEAS

Doomblade187

  • Bay Watcher
  • Requires music to get through the working day.
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10663 on: December 09, 2017, 10:38:50 am »

Hey there, programmer folk. Can any of you recommend a good free 2D game engine? Being beginner friendly is a plus. I have considered GameMaker for this, but would rather not.
Logged
In any case it would be a battle of critical thinking and I refuse to fight an unarmed individual.
One mustn't stare into the pathos, lest one become Pathos.

Reelya

  • Bay Watcher
    • View Profile
Re: if self.isCoder(): post() #Programming Thread
« Reply #10664 on: December 09, 2017, 11:27:17 am »

You should probably just learn to use Unity. It does 2D and 3D and is industry standard.

As for lower-tier stuff, it really depends exactly what you want to make. If you want something that's more "snap-together", then it's genre specific, such as Ren'py for visual novels or rpgmaker for top-down rpgs. Those give you a fully-fleshed out toolchain for making content and getting things running "out of the box", however the trade-off is that you're working within their specific framework and the assumptions they've made about the type of game you're creating.
« Last Edit: December 09, 2017, 11:35:57 am by Reelya »
Logged
Pages: 1 ... 709 710 [711] 712 713 ... 796