Using multiprocessing issue with Kivy

I do not understand how to combine multiprocessing with Kivy, a Python GUI library, so please help me on this.

Initially, I had created a code using Kivy, a Python GUI library, and threading.Thread, as follows.

#-*- coding: utf-8 -*-

from kivy.lang import Builder
Builder.load_string("""
<TextWidget>:
    BoxLayout:
        orientation: 'vertical'
        size: root.size

        Button:
            id: button1
            text: "start"
            font_size: 48
            on_press: root.buttonClicked()
""")

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.properties import StringProperty 
import threading
import time

class TextWidget(Widget):
	def __init__(self, **kwargs):
		super(TextWidget, self).__init__(**kwargs)
		self.process_test = None
		
	def p_test(self):
		i = 0
		while True:
			print(i)
			i = i + 1
			
			if self.ids.button1.text == "start":
				break

	def buttonClicked(self):
		if self.ids.button1.text == "start":
			self.process_test = threading.Thread(target=self.p_test)
			self.process_test.start()
			self.ids.button1.text = "stop"
		else:
			self.ids.button1.text = "start"
			self.process_test.join()
            

class TestApp(App):
	def __init__(self, **kwargs):
		super(TestApp, self).__init__(**kwargs)
		self.title = 'testApp'

	def build(self):
		return TextWidget()

if __name__ == '__main__':
	TestApp().run()

This code simply displays a single button, and when the button is pressed, it executes a print statement in a while loop.

This code, being a simple example, worked without any issues.

However, as the Kivy GUI definition file became larger, and the CPU processing load of the program running inside the p_test function increased, the program started to become choppy.

According to my machine’s task manager, despite having plenty of CPU capacity, it seemed there were limitations to processing everything within a single process.

To circumvent this issue, I decided to use multiprocessing. However, I find the use of multiprocessing complex and hard to understand, so I would like to learn more about how to use it.

First, I replaced the threading.Thread in my earlier code with multiprocessing.Process as follows.

#-*- coding: utf-8 -*-

from kivy.lang import Builder
Builder.load_string("""
<TextWidget>:
    BoxLayout:
        orientation: 'vertical'
        size: root.size

        Button:
            id: button1
            text: "start"
            font_size: 48
            on_press: root.buttonClicked()
""")

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.properties import StringProperty 
import time
from multiprocessing import Process

class TextWidget(Widget):
	def __init__(self, **kwargs):
		super(TextWidget, self).__init__(**kwargs)
		self.process_test = None
		
	def p_test(self):
		i = 0
		while True:
			print(i)
			i = i + 1
			
			if self.ids.button1.text == "start":
				break

	def buttonClicked(self):
		if self.ids.button1.text == "start":
			self.process_test = Process(target=self.p_test, args=())
			self.process_test.start()
			self.ids.button1.text = "stop"
		else:
			self.ids.button1.text = "start"
			self.process_test.join()
            

class TestApp(App):
	def __init__(self, **kwargs):
		super(TestApp, self).__init__(**kwargs)
		self.title = 'testApp'

	def build(self):
		return TextWidget()

if __name__ == '__main__':
	TestApp().run()

Unfortunately, this code did not work correctly and resulted in an error. The error message was as follows.

 Traceback (most recent call last):
   File "<string>", line 1, in <module>
   File "C:\Users\taichi\Documents\Winpython64-3.11.5.0\WPy64-31150\python-3.11.5.amd64\Lib\multiprocessing\spawn.py", line 122, in spawn_main
     exitcode = _main(fd, parent_sentinel)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
   File "C:\Users\taichi\Documents\Winpython64-3.11.5.0\WPy64-31150\python-3.11.5.amd64\Lib\multiprocessing\spawn.py", line 132, in _main
     self = reduction.pickle.load(from_parent)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 EOFError: Ran out of input

I learned that I must use multiprocessing directly under if **name** == '**main** ':. However, this makes it difficult to pass values between Kivy and the multiprocessing code, and I’m not sure how to handle it.

The code I created as a trial is as follows.

#-*- coding: utf-8 -*-

from kivy.lang import Builder
Builder.load_string("""
<TextWidget>:
    BoxLayout:
        orientation: 'vertical'
        size: root.size

        Button:
            id: button1
            text: "start"
            font_size: 48
            on_press: root.buttonClicked()
""")

from kivy.app import App
from kivy.uix.widget import Widget

from kivy.properties import StringProperty 
import threading
import time
from multiprocessing import Process

class TextWidget(Widget):
	def __init__(self, **kwargs):
		super(TextWidget, self).__init__(**kwargs)
		self.process_test = None
				
	def buttonClicked(self):
		if self.ids.button1.text == "start":
			self.ids.button1.text = "stop"
		else:
			self.ids.button1.text = "start"
            

class TestApp(App):
	def __init__(self, **kwargs):
		super(TestApp, self).__init__(**kwargs)
		self.title = 'testApp'

	def build(self):
		return TextWidget()

def p_test(count, array):
	i = 0
	while True:
		print(i)
		i = i + 1

if __name__ == '__main__':
	#shared memory
	count = Value('i', 0)
	array = Array('i', 0)

	process_kivy = Process(target=TestApp().run(), args=[count, array])
	process_kivy.start()
	
	process_test = Process(target=p_test(), args=[count, array])
	process_test.start()
	
	process_kivy.join()
	process_test.join()

I created the above code because I learned that using shared memory allows for data sharing between multiprocessing instances. However, I don’t understand how to pass data to a class with shared memory.

I want to set it up so that the while loop starts only when a Kivy’s button is pressed, but in reality, the print statement is executed after the Kivy GUI is closed in this code.

Furthermore, since the Kivy program also needs to be launched with multiprocessing, I don’t know how to join my own process to itself.

How can I use multiprocessing correctly?

Hello,
here is a link which should explain more about using MP with Kivy and data transfer via mp.Queue
and how to avoid the second blank kiv-window (sorry no shared memory)

kivy multiprocessing example

1 Like

Thank you very much.
It worked as I expected.