Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Solved] How to load sf.Images in a separate Thread/process?  (Read 6968 times)

0 Members and 1 Guest are viewing this topic.

AClockWorkLemon

  • Newbie
  • *
  • Posts: 20
    • View Profile
[Solved] How to load sf.Images in a separate Thread/process?
« on: October 14, 2011, 08:05:00 am »
Heya!

I was hoping someone could outline how to load images in a separate thread/process with PySFML. I gave Thread a go, and found that it was blocking the PySFML thread. After searching around for a bit, i found Process, which didn't block the main thread at all. However, i have been unable to send the data of the loaded images to any other threads. (Python interpreter complains about being unable to pickle the Image)

If anyone could help sort out this issue, it'd be greatly appreciated!

AClockWorkLemon

  • Newbie
  • *
  • Posts: 20
    • View Profile
[Solved] How to load sf.Images in a separate Thread/process?
« Reply #1 on: October 19, 2011, 01:53:54 am »
Sorry to bump, but i cannot for the life of me find a working answer :/

Normally the loading of images isn't a huge problem, however for this project, it will need to load some ~270 images, each up to about 5MB in size. Unless i find a way of loading quickly, or loading in a separate process, it is going to be far too slow :/

bastien

  • Full Member
  • ***
  • Posts: 231
    • View Profile
    • http://bastien-leonard.alwaysdata.net
[Solved] How to load sf.Images in a separate Thread/process?
« Reply #2 on: October 19, 2011, 02:50:40 pm »
I've never used threads to load images, but here is a basic example.
I assume that you have some work to do in parallel of the image loading. Otherwise, you will probably need more complex synchronization mechanisms.

Honestly, this is unlikely to give better performance overall, unless the GIL is released before doing I/O-heavy operations.

Have you tried loading the images on demand?

Code: [Select]
import threading

import sf


SPRITES = ['file1.png', 'file2.png']


class LoadingThread(threading.Thread):
    def __init__(self, sprites):
        threading.Thread.__init__(self)
        self.sprites = sprites

    def run(self):
        for filename in SPRITES:
            self.sprites.append(sf.Sprite(sf.Texture.load_from_file(filename)))


def main():
    window = sf.RenderWindow(sf.VideoMode(640, 480), 'Title')
    window.framerate_limit = 60
    sprites = []
    thread = LoadingThread(sprites)
    thread.start()

    # Do some work while the images are being loaded

    thread.join()
    running = True

    while running:
        for event in window.iter_events():
            if event.type == sf.Event.CLOSED:
                running = False

        window.clear(sf.Color.WHITE)

        for sprite in sprites:
            window.draw(sprite)

        window.display()


if __name__ == '__main__':
    main()
Check out pysfml-cython, an up to date Python 2/3 binding for SFML 2: https://github.com/bastienleonard/pysfml-cython

AClockWorkLemon

  • Newbie
  • *
  • Posts: 20
    • View Profile
[Solved] How to load sf.Images in a separate Thread/process?
« Reply #3 on: October 20, 2011, 02:46:44 am »
Thanks for that. The main issue is that the first screen will be showing them all. And also, i don't have anything else to do while the images load :/

I already have the "Thumbnail" objects checking a dict to see if their Image has been loaded. Currently, because the images are all loaded in-line, they all appear at once. I was wondering if it would be possible to split a thread/process off to load the images, and put references in the dict (or whatever) so that the Thumbnails all load with the "loading" image, which is replaced by the final image once it has been loaded. Obviously for this to work, the SFML loop would need to be running...

Not sure how descriptive that explanation is, i'm not sure how to explain it very well.

bastien

  • Full Member
  • ***
  • Posts: 231
    • View Profile
    • http://bastien-leonard.alwaysdata.net
[Solved] How to load sf.Images in a separate Thread/process?
« Reply #4 on: October 20, 2011, 02:47:49 pm »
In this case, something like that would work. Note that the boolean can't be passed as a an argument if you want the thread to be able to modify it, because bools are immutable. That's the main reason why I created the ThreadData class.
Normally, you would probably need a mutex or a thread-safe list, but because of the GIL, I decided to make it simple for this example.

Code: [Select]
import glob
import threading

import sf


SPRITES = glob.iglob('/media/winxp/d/images/Textures/2D/TEXTURES/*.BMP')


class ThreadData(object):
    def __init__(self, sprites):
        self.sprites = sprites
        self.join_thread = False


class LoadingThread(threading.Thread):
    def __init__(self, data):
        threading.Thread.__init__(self)
        self.data = data

    def run(self):
        for i, filename in enumerate(SPRITES):
            sprite = sf.Sprite(sf.Texture.load_from_file(filename))
            self.data.sprites.append(sprite)

        self.data.join_thread = True
        print 'Finished loading'


def main():
    window = sf.RenderWindow(sf.VideoMode(1280, 1024), 'Title')
    window.framerate_limit = 60
    sprites = []
    thread_data = ThreadData(sprites)
    thread = LoadingThread(thread_data)
    thread.start()
    running = True

    while running:
        for event in window.iter_events():
            if event.type == sf.Event.CLOSED:
                running = False

        if thread_data.join_thread:
            thread.join()
            thread_data.join_thread = False
            print 'Joined'

        window.clear(sf.Color.WHITE)

        for sprite in sprites:
            window.draw(sprite)

        window.display()


if __name__ == '__main__':
    main()


Did you try to write a sample in C++, to see if it would speed things up? I'm interested to see if the binding needs to be optimized.
Check out pysfml-cython, an up to date Python 2/3 binding for SFML 2: https://github.com/bastienleonard/pysfml-cython

AClockWorkLemon

  • Newbie
  • *
  • Posts: 20
    • View Profile
[Solved] How to load sf.Images in a separate Thread/process?
« Reply #5 on: October 21, 2011, 03:24:01 am »
Oops, never mind. Error my end. Thanks for that, much appreciated!

And no, i haven't done any work on this in C++. My mind just doesn't handle it well enough yet ^_^