funk
funk

Reputation: 1

simple thread management within python classes

Im trying to write a module for Python that prints out text for my program and displays a progress bar while i do something in the background. Im using the 'threading' module currently but open to suggestions if something else will make it easier.

what i want to know is two fold, how should i call this class elegantly and how should i stop these threads im creating?

this is what im currently doing:

tmp1 = textprint("hello this is text")
tmp1.start()
# do something
tmp1.stop()

these are the options ive considered and looked into so far:

what i would like to do is something like this:

echo('hello') (prints progress bar etc) - and then when i want to stop it echo.stop()

the obv. problem there though is that the stop function doesnt know which thread it is trying to stop.

Here is a skeleton of what im trying to do:

import time
import string
import threading

class print_text(threading.Thread):

    def __init__(self,arg=None):
        super(print_text,self).__init__()
        self._stop = False
        self.arg=arg

    def run (self):
        # start thread for text
        print self.txt
        while not self._stop:
                print "rude words"

    def echo (self,txt):
        self.txt=txt
        self.start()

    def stop(self):
        self._stop = True

    def stopped(self):
        return self._stop == True

    def __enter__(self):
        print "woo"
        return thing

    def __exit__(self, type, value, traceback):
        return isinstance(value, TypeError)


if __name__ == '__main__':

    print_text.start.echo('this is text') # dunt werk

    with print_text.echo('this is text'):
           time.sleep(3)

    print "done"

and then call it like so:

echo('this is text') 

i also guess to do this i would have to

import echo from print_text 

the WITH way of doing things suggests putting an __enter__ and __exit__ bit in. i tried them and they didnt work and also, i didnt know what i was doing, really appreciate any help, thanks.

Upvotes: 2

Views: 5269

Answers (3)

Dave
Dave

Reputation: 3956

A thread name is useful if you could potentially have multiple subthreads running the same target at once and want to ensure that all of them are stopped. It seems like a useful generalization and doesn't seem too cumbersome to me, but beauty is in the eye of the beholder :-). The following:

  • starts a subthread to print a message and start a progressbar
  • stops the subthread using a name given when it was started.

It is much simpler code. Does it do what you want?

import time, threading

class print_text:

    def __init__(self):
        pass

    def progress(self):
        while not self._stop:       # Update progress bar
            print(".", sep="", end="")
            time.sleep(.5)

    def echo(self, arg="Default"):  # Print message and start progress bar
        print(arg)
        self._stop = False
        threading.Thread(target=self.progress, name="_prog_").start()

    def stop(self):
        self._stop = True
        for t in threading.enumerate():
            if t.name == "_prog_":
                t.join()

tmp1 = print_text()
tmp1.echo("hello this is text")
time.sleep(10)
tmp1.stop()
print("Done")

Upvotes: 0

Raymond Hettinger
Raymond Hettinger

Reputation: 226754

You were very close to having working code. There just needed to be a few minor fixups:

  • print_text is a class. It should be instantiated with print_text()
  • The start method returns an instance of print_text, you need to save that in order to call stop and echo on it: t = print_text()
  • The enter method needs to return self instead of thing.
  • The exit method should either set _stop or call stop().
  • The echo method should return self so that it can be used with the with-statement.

Here is some working code that includes those minor edits:

import time
import string
import threading

class print_text(threading.Thread):

    def __init__(self, arg=None):
        super(print_text,self).__init__()
        self._stop = False
        self.arg=arg

    def run (self):
        # start thread for text
        print self.txt
        while not self._stop:
                print "rude words"

    def echo (self, txt):
        self.txt=txt
        self.start()
        return self

    def stop(self):
        self._stop = True

    def stopped(self):
        return self._stop == True

    def __enter__(self):
        print "woo"
        return self

    def __exit__(self, type, value, traceback):
        self._stop = True
        return isinstance(value, TypeError)


if __name__ == '__main__':

    t = print_text()
    t.echo('this is text')
    time.sleep(3)
    t.stop()

    with print_text().echo('this is text'):
        time.sleep(3)

    print "done"

Upvotes: 4

Eli Bendersky
Eli Bendersky

Reputation: 273854

The best way to stop a thread in Python is to politely ask it to stop. The best way to pass new data to a thread is with the Queue module.

Both are used in the code in this post, which demonstrates socket communication from a Python thread but is otherwise relevant to your question. If you read the code carefully you'll notice:

  1. Using threading.Event() which is set by a method call from outside, and which the thread periodically checks to know if it was asked to die.
  2. Using Queue.Queue() for both passing commands to the thread and receiving responses from it.

Upvotes: 3

Related Questions