Threads vs Processes

John Henry john106henry at hotmail.com
Thu Jul 27 13:30:41 EDT 2006


Nick Craig-Wood wrote:
>
> Here is test prog...
>

<snip>

Here's a more real-life like program done in both single threaded mode
and multi-threaded mode.  You'll need PythonCard to try this.  Just to
make the point, you will notice that the core code is identical between
the two (method on_menuFileStart_exe).  The only difference is in the
setup code.  I wanted to dismiss the myth that multi-threaded programs
are inherently *evil*, or that it's diffcult to code, or that it's
unsafe.....(what ever dirty water people wish to throw at it).

Don't ask me to try this in process!

To have fun, first run it in single threaded mode (change the main
program to invoke the MyBackground class, instead of the
MyBackgroundThreaded class):

Change:

	app = model.Application(MyBackgroundThreaded)

to:

	app = model.Application(MyBackground)

Start the process by selecting File->Start, and then try to stop the
program by clicking File->Stop.  Note the performance of the program.

Now, run it in multi-threaded mode.  Click File->Start several times
(up to 4) and then try to stop the program by clicking File->Stop.

If you want to show off, add several more StaticText items in the
resource file, add them to the textAreas list in MyBackgroundThreaded
class and let it rip!

BTW: This ap also demonstrates the weakness in Python thread - the
threads don't get preempted equally (not even close).

:-)

Two files follows (test.py and test.rsrc.py):

#!/usr/bin/python

"""
__version__ = "$Revision: 1.1 $"
__date__ = "$Date: 2004/10/24 19:21:46 $"
"""

import wx
import threading
import thread
import time

from PythonCard import model

class MyBackground(model.Background):

	def on_initialize(self, event):
		# if you have any initialization
		# including sizer setup, do it here
		self.running(False)
		self.textAreas=(self.components.TextArea1,)
		return

	def on_menuFileStart_select(self, event):
		on_menuFileStart_exe(self.textAreas[0])
		return

	def on_menuFileStart_exe(self, textArea):
		textArea.visible=True
		self.running(True)
		for i in range(10000000):
			textArea.text = "Got up to %d" % i
			##            print i
			for j in range(i):
				k = 0
				time.sleep(0)
				if not self.running(): break
			try:
				wx.SafeYield(self)
			except:
				pass
			if not self.running(): break
		textArea.text = "Finished at %d" % i
		return

	def on_menuFileStop_select(self, event):
		self.running(False)

	def on_Stop_mouseClick(self, event):
		self.on_menuFileStop_select(event)
		return

	def running(self, flag=None):
		if flag!=None:
			self.runningFlag=flag
		return self.runningFlag


class MyBackgroundThreaded(MyBackground):

	def on_initialize(self, event):
		# if you have any initialization
		# including sizer setup, do it here
		self.myLock=thread.allocate_lock()
		self.myThreadCount = 0
		self.running(False)
		self.textAreas=[self.components.TextArea1, self.components.TextArea2,
self.components.TextArea3, self.components.TextArea4]
		return

	def on_menuFileStart_select(self, event):
		res=MyBackgroundWorker(self).start()

	def on_menuFileStop_select(self, event):
		self.running(False)
		self.menuBar.setEnabled("menuFileStart", True)

	def on_Stop_mouseClick(self, event):
		self.on_menuFileStop_select(event)

	def running(self, flag=None):
		self.myLock.acquire()
		if flag!=None:
			self.runningFlag=flag
		flag=self.runningFlag
		self.myLock.release()
		return flag

class MyBackgroundWorker(threading.Thread):
	def __init__(self, parent):
		threading.Thread.__init__(self)
		self.parent=parent
		self.parent.myLock.acquire()
		threadCount=self.parent.myThreadCount
		self.parent.myLock.release()
		self.textArea=self.parent.textAreas[threadCount]

	def run(self):
		self.parent.myLock.acquire()
		self.parent.myThreadCount += 1
		if self.parent.myThreadCount==len(self.parent.textAreas):
			self.parent.menuBar.setEnabled("menuFileStart", False)
		self.parent.myLock.release()

		self.parent.on_menuFileStart_exe(self.textArea)

		self.parent.myLock.acquire()
		self.parent.myThreadCount -= 1
		if self.parent.myThreadCount==0:
			self.parent.menuBar.setEnabled("menuFileStart", True)
		self.parent.myLock.release()

		return

if __name__ == '__main__':
	app = model.Application(MyBackgroundThreaded)
	app.MainLoop()



Here's the associated resource file:

{'application':{'type':'Application',
          'name':'Template',
    'backgrounds': [
    {'type':'Background',
          'name':'bgTemplate',
          'title':'Standard Template with File->Exit menu',
          'size':(400, 300),
          'style':['resizeable'],

        'menubar': {'type':'MenuBar',
         'menus': [
             {'type':'Menu',
             'name':'menuFile',
             'label':'&File',
             'items': [
                  {'type':'MenuItem',
                   'name':'menuFileStart',
                   'label':u'&Start',
                  },
                  {'type':'MenuItem',
                   'name':'menuFileStop',
                   'label':u'Sto&p',
                  },
                  {'type':'MenuItem',
                   'name':'menuFile--',
                   'label':u'--',
                  },
                  {'type':'MenuItem',
                   'name':'menuFileExit',
                   'label':'E&xit',
                   'command':'exit',
                  },
              ]
             },
         ]
     },
         'components': [

{'type':'StaticText',
    'name':'TextArea1',
    'position':(10, 100),
    'text':u'This is a test',
    'visible':False,
    },

{'type':'StaticText',
    'name':'TextArea2',
    'position':(160, 100),
    'text':u'This is a test',
    'visible':False,
    },

{'type':'StaticText',
    'name':'TextArea3',
    'position':(10, 150),
    'text':u'This is a test',
    'visible':False,
    },

{'type':'StaticText',
    'name':'TextArea4',
    'position':(160, 150),
    'text':u'This is a test',
    'visible':False,
    },

] # end components
} # end background
] # end backgrounds
} }




More information about the Python-list mailing list