[Tutor] Threaded FTP class

Kent Johnson kent37 at tds.net
Tue Oct 10 03:10:10 CEST 2006


Bill Burns wrote:
> I'm trying to make a small, threaded FTP app and I'm running into
> a problem.
> 
> My program has a GUI (I use PythonCard) and I want the GUI to be
> responsive while network operations are going on.
> 
> I assumed that if I made a class (shown below) which was sub-classed
> from threading.Thread - I wouldn't have any problems.
> 
> My GUI class (not shown) has a 'connect' button with a method that
> looks like this:
> 
> def on_connect_command(self, event):
>      """Connect to the remote server."""
>      # getConnectData() -> returns a tuple with
>      # all of the data we need to connect.
>      server, username, password = self.getConnectData()
>      # Instantiate my threaded FTP class.
>      self.host = FTP(server, username, password)
>      self.host.setDaemon(True)
>      self.host.start()
>      time.sleep(1)
> 
> When I hit this button, the GUI is completely responsive while trying to
> connect to the remote server. I have no problems and everything works as
> expected.

In this method you create a new thread and start it. The thread's run() 
method is called. It connects to the remote server, fetches and prints a 
directory and returns. At that point (when the run() method returns) the 
FTP thread is dead.
> 
> Here's where I get the problem... The GUI class has another method which
> looks like this:
> 
> def on_getData_command(self, event):
>      # getDirectoryData(...) is a method in the
>      # FTP() class. It walks a remote directory.
>      self.host.getDirectoryData(someDirectory)
> 
> When I fire this method - it blocks until getDirectoryData() returns,
> which makes the GUI non-responsive. It's *not* hanging due to a network
> problem (it will only fire if you're connected to the remote server.)
> 
> Why does this one method block? I assumed it would run in the FTP class
> thread and I'd have no problems!? What should I do different?

No, you don't do anything here to make the getDirectoryData() method run 
in a separate thread. Just because the FTP class has (or had) one thread 
at one time doesn't automatically make all of the FTP class methods run 
in a different thread.

There are a few different ways you could handle this. You could have 
each command in the FTP class be smart enough to start a new thread to 
run the command. You don't actually have to subclass threading.Thread, 
you can just create a thread and tell it what method to execute. (Side 
note - this might be a good use for a @run_in_thread decorator.)

You could make a separate class for each command. This would be pretty 
similar to the above solution. You would probably want a base class or 
utility class to hold the common details of connecting and sending a 
command.

You could make a thread that really does keep running, that listens to 
for commands from a Queue. Your GUI thread would put a command in the 
Queue, the daemon thread would pull a command out and execute it.

You could figure out how to do this with Twisted...

HTH,
Kent




More information about the Tutor mailing list