[Jython-users] Writing Threaded Applications in Jython
by Frank Cohen other posts by this author
Mar 25 2004 7:11PM messages near this date
[Jython-users] hello
|
[Jython-users] Statement execfile()
As a contribution back to the Jython community, I wrote an article that
describes the various options Jython users have to write threaded
applications. The complete and formatted article is available on the
PushToTest Web site at:
http://www.pushtotest.com/Docs/howto/jythonthreads.html
I have also copied the text of the article below. I am open to
feedback, corrections, and additions. Hopefully this will be a living
document as Jython grows.
My thanks goes to Clark Updike (Clark.Updike@jhuapl.edu), Jeff Emanuel
(jemanuel@lgc.com), Fred Sells (fred@adventistcare.org) for providing
feedback, comments, and help.
---
Writing Threaded Applications in Jython
Abstract:
Jython is a popular object oriented scripting language among software
developers, QA technicians, and IT managers. It is also the scripting
language in TestMaker and TestNetwork. In this article, Frank Cohen
looks at Jythons ability to construct threaded multi-tasking software,
shows the best practice to build scalable and thread-safe code, and
points out how to avoid common mistakes and misunderstandings
Feel free to share this document in its entirety with your
friends and associates; However, this document remains
© 2004 Frank Cohen. All rights reserved.
Jython and Threading
Jython is an object oriented scripting language that is popular with
software developers, QA technicians, and IT managers. Jython is a 100%
Java application. At runtime Jython scripts compile into Java bytecodes
and run in the Java virtual machine. Jython classes are first class
Java objects, so Jython can import any Java object on the classpath and
call its methods. Jython gives Java developers the best of both worlds.
Consequently, more and more test automation software, installation
scripts, system monitoring code, and utility script code is being
written in Jython.
Jython provides an easy environment to build objects. One of my first
Jython scripts looked like this:
class myclass:
def setMyparam( self, myparam ):
self.storeit = myparam
def getMyparam( self ):
return self.storeit
a = myclass()
a.setMyparam( "frank" )
b = myclass()
b.setMyparam( "lorette" )
print "a.storeit =", a.getMyparam()
print "b.storeit =", b.getMyparam()
This script implements a class name myclass. It has two methods, one to
set a parameter and the second to get the stored value. Here is the
output when I run the script:
a = frank
b = lorette
While this is straightforward enough, I envision using an object like
myclass in a threaded application. These questions come to mind:
Which dictionary is the storeit variable stored?
Do I have to worry that some other call to another instance of myclass
will get the storeit value from the wrong instance?
Is myclass thread safe?
Jython stores variables in dictionaries. Each new class gets its own
dictionary when Jython instantiates the class. In myclass, self.storeit
refers to the instance of storeit in the dictionary for the instance of
myclass. As long as the script uses self.storeit then no other instance
of myclass will get the self.storeit value. However, imagine the script
includes a bug such as:
def getMyparam ( self ):
return storeit
In this example, I forgot to use self.storeit in the getMyparam method.
Jython implements the equivalent of a Java Static class when myclass is
defined in the script. This faulty print method retrieves the storeit
value from the static class version of myclass and not from the
instance of myclass referred to by a or b.
When multiple threads concurrently call setMyparam on the same instance
of myclass, then it is anyones guess which thread uses the setMyparam
method last and actually sets the final value of Myparam. This is
commonly referred to as a race condition. Consider the following
example program:
import thread
class myclass:
def setMyparam( self, myparam ):
self.storeit = myparam
def getMyparam( self ):
return self.storeit
def runthenumbers( a, name ):
for i in range(100):
print name, ",", a.getMyparam()
a.setMyparam( i * 2 )
a = myclass()
a.setMyparam( "frank" )
thread.start_new_thread( runthenumbers, ( a, "Thread 1",) )
thread.start_new_thread( runthenumbers, ( a, "Thread 2",) )
This script defines myclass with two methods: one to set a value and
one to get a value. Then it defines a runthenumbers method that gets
the value from a myclass object, prints it to the screen, and stores a
new myclass value. The script then instantiates a myclass that will be
referred to by a and sets the initial value to frank. Lastly, the
script instantiates two concurrently running threads that operate on
the instance of myclass.
When the script runs, both threads use the setMyparam and getMyparam
method of myclass. It is likely that eventually one thread will
interrupt the other when using setMyparam. In this case it anyones
guess which threads call to setMyparam stores the final value since
threads are meant to run concurrently by timesharing the system
resources. In summary, this approach to coding a threaded application
has these problems:
You have no way of telling the conditions of the threads: Have they
started? Have they finished?
Multiple threads may try to call setMyparam concurrently. In the
ensuing race condition, the last thread to call setMyparam wins. And
there is no way to tell.
This is not to say that Jython cannot produce thread safe code. Jython
does! However, there are multiple designs to create thread safe classes
that avoid these problems.
The Many Ways To Thread An Application in Jython
Jython's ability to use Java objects introduces a variety of options
when it comes to building threaded applications. This section describes
four options and examines their relative merits and problems.
Python Threads
This example uses the Jython thread library. However, to overcome
possible race conditions the script uses Jython's synchronized library
to guarantee that only one thread can call a method at a time:
import thread, synchronize
class myclass:
def setMyparam( self, myparam ):
self.storeit = myparam
setMyparam=synchronize.make_synchronized( setMyparam )
def getMyparam( self ):
return self.storeit
getMyparam=synchronize.make_synchronized( getMyparam )
def runthenumbers( a, name ):
for i in range(100):
print name, ",", a.getMyparam()
a.setMyparam( i * 2 )
a = myclass()
a.setMyparam( "frank" )
thread.start_new_thread( runthenumbers, ( a, "Thread 1",) )
thread.start_new_thread( runthenumbers, ( a, "Thread 2",) )
In this example, make_synchonized uses the same technique as Java to
synchronize method calls. Jython implements the synchronize library
using this Java code:
public static PyObject make_synchronized(PyObject callable)
{
return new SynchronizedCallable(callable);
}
and SynchronizedCallable has a __call__ operator to call the argument
callable's __call__ method in a synchronized block like this:
synchronized(synchronize._getSync(arg))
{
return callable.__call__(arg);
}
Python Threads provides an easy way in a Jython script to create a
threaded application and synchronized thread safe methods within a
class object. A newer Python technique uses the Threading library. Here
is an example:
import threading
def greet( name ):
print "greetings", name
count = 0
t = threading.Thread(
target=greet,
name="MyThread %d" % count,
args=( "threading.Thread", )
)
t.start()
The new Python technique provides a slightly more Java-like feel to the
syntax to create threads and provides a simple way to name a thread.
Aside from those advantages I observe no performance or functional
difference from the older Python technique.
Java Threads
This example uses the Java Thread library to implement a threaded
example:
from java.lang import Thread, Runnable
class GreetJob( Runnable ):
def __init__( self, name ):
self.name = name
def run( self ):
print self.name
count = 1
t = Thread( GreetJob( "Runnable" ), "MyThread %d" % count )
t.start()
Jython can also implement threads by extending the Java Thread class.
Between these two techniques I have observed no differences in
performance or functionality:
from java.lang import Thread
class GreetThread( Thread ):
def __init__( self, name, count ):
Thread.__init__( self, "MyThread %d" % count )
self._name = name # Thread has a 'name' attribute
def run( self ):
print self._name
count = 2
t = GreetThread( "Thread subclass", count )
t.start()
I find it very unusual in a Python environment to have so many
different ways to accomplish the same goal. Especially considering
Python has a "one obvious way to do it" design principle. Therefore,
next I describe what I believe to be the best practice to design Jython
scripts that implement threads.
The Best Practice
Based on my experience writing threaded applications in Jython, using
Java Threads and the Runnable interface is the best practice. The
following Jython script implements the best practice for building
threaded applications in Jython:
from java.lang import Thread, Runnable
import synchronize
class myclass( Runnable ):
def __init__( self, myparam ):
self.storeit = myparam
def setMyparam( self, myparam ):
self.storeit = myparam
setMyparam=synchronize.make_synchronized( setMyparam )
def printMyparam( self ):
print "myclass: myparam =",self.storeit
printMyparam=synchronize.make_synchronized( printMyparam )
def run( self ):
for self.i in range(5):
self.printMyparam()
count = 2
a = myclass()
a.setMyparam( "frank" )
t = Thread( a, "MyThread %d" % count )
t.start()
In summary, the best practice makes these points:
The above code example defines myclass to implement the Runnable
interface from the Java Thread object. Runnable works best because it
offers the thread management APIs to check status, set daemon thread
status, and kill a thread.
I use the make_synchronized method of the synchronize library to make
certain that only only one call to the method is possible at any given
time.
The __init__ method creates the storeit object and sets the initial
value. When the class is instantiated Jython calls the __init__ method
on the instance of the new class so there is no need to synchronize
__init__ because only the new instantiation of the class has access to
it. __init__ is thread safe.
Joining Threads
An additional technique supported by the Java Thread technique is that
threads may be joined. Your scripts use the current thread and one new
thread and then "join" the threads so the current thread doesn't
proceed until the new one finishes. Here's an example of that:
import threading
import time
def pause(threadName, sleepSeconds):
# create an attribute
threading.currentThread.isDone = 0
print "Thread %s is sleeping for %s seconds." % (threadName, sleepSeconds)
time.sleep(sleepSeconds)
print "Thread %s is waking up." % threadName
threading.currentThread().isDone = 1
newThread = threading.Thread(name='newThread', target=pause,args=('newThread',3))
newThread.start()
# use the current thread too
pause('currentThread',1)
# wait for newThread to finish
newThread.join()
# make sure they are both done
assert(newThread.isDone and threading.currentThread().isDone)
print "Both threads were done executing pause"
When running the script above I see the following output:
Thread newThread is sleeping for 3 seconds.
Thread currentThread is sleeping for 1 seconds.
Thread currentThread is waking up.
Thread newThread is waking up.
Both threads were done executing pause
Java's Thread class also has a join method if you use Java's threads.
Where To Find Example Code
Download all the example code in this article at
http://docs.pushtotest.com.
Where To Find Additional Information
Try these URLs for information that helped me write this article:
http://www.strakt.com/docs/eup02_threads_jacob.pdf
http://aspn.activestate.com/ASPN/Mail/Message/Jython-users/1051825
https://lists.sourceforge.net/lists/listinfo/jython-users
http://www.jython.org
http://www.pushtotest.com
About The Author
Frank Cohen is the "go to" guy for enterprises needing to test and
solve problems in complex interoperating information systems,
especially Web Services. Frank is founder of PushToTest, a test
automation solutions business and author of Java Testing and Design:
From Unit Tests to Automated Web Tests (Prentice Hall.) Frank maintains
TestMaker, a free open-source utility that uses Jython to build
intelligent test agents to check Web Services for scalability,
performance and functionality. PushToTest Global Services customizes
TestMaker to an enterprise's specific needs, conducts scalability and
performance tests, and trains enterprise developers, QA technicians and
IT managers on how to use the test environment for themselves. Details
are at www.pushtotest.com. Contact Frank at fcohen@[...].com.
-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id70&alloc_id638&opÌk
_______________________________________________
Jython-users mailing list
Jython-users@[...].net
https://lists.sourceforge.net/lists/listinfo/jython-users
|