[prev in list] [next in list] [prev in thread] [next in thread]
List: python-list
Subject: Re: How to convert a train running program from synchronous to asynchronous?
From: Irv Kalb <Irv () furrypants ! com>
Date: 2019-04-26 20:28:07
Message-ID: A5486ED7-83DC-40C0-AEDA-8CF13F01BD58 () furrypants ! com
[Download RAW message or body]
> On Apr 26, 2019, at 4:18 AM, Arup Rakshit <ar@zeit.io> wrote:
>
> I have modelled which starts running once drivers and stations are assigned to it. \
> Otherwise, it doesn't run, really don't care if passengers are boarded or not at \
> this moment. :) I think this program can help me to introduce to the Python async \
> programming domain.
> Here is my program:
>
> # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # train.py
> # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> import time
> import random
>
> from user import User
>
> class NotReadyToDeparture(Exception):
> pass
>
> class Train:
> def __init__(self, name, category):
> self.name = name
> self.category = category
> self.__drivers = []
> self.__stations = []
>
> @property
> def drivers(self):
> return self.__drivers
>
> @drivers.setter
> def drivers(self, coachmen):
> self.__drivers = coachmen
>
> @property
> def stations(self):
> return self.__stations
>
> @stations.setter
> def stations(self, places):
> self.__stations = places
>
> def next_stoppage(self):
> return self.stations[0]
>
> def run(self):
> total_run_time = 0
> if len(self.drivers) == 0:
> raise NotReadyToDeparture('Drivers are not yet boarded')
>
> if len(self.stations) == 0:
> raise NotReadyToDeparture('Stoppage stations are not yet scheduled')
>
> for station in range(len(self.stations[:])):
> run_time_to_next_stoppage = random.randint(2, 6)
> time.sleep(run_time_to_next_stoppage)
> total_run_time += run_time_to_next_stoppage
> print("Train Reached at {0} in {1} seconds".format(self.stations.pop(0), \
> run_time_to_next_stoppage))
> print(f"Train {self.name} is reached the destination in {total_run_time} seconds.")
>
The underlying problem with your current "run" method is that it only returns when \
the train has visited all the stations. This happens because of your for loop and \
the call to time.sleep inside your loop.
Instead, I would suggest that you split the functionality of your current run method \
into two methods. The "run" method would start the train going. Then you need a \
separate method, maybe "update" that would be called continuously. (Code below is \
completely untested)
The run method would consist of your current checks to ensure that the drivers and \
stations are set. Then, it should set:
self.total_run_time = 0 # making this an instance variable that will be used \
in the update method
You also need a way of getting the current (real) time so you can know when you have \
reached the next station (I'll leave the implementation of that up to you):
self.stations.insert(0, 'start') # add something at the beginning of your \
list that will get popped off immediate at the first call to update \
self.time_at_next_station = <get the current time>
The update method will be called continuously. It should check the current time and \
see if it has reached the time to move on to the next station, something like:
def update():
currentTime = <get the current time>
if currentTime < self.time_at_next_station: # in transit to the next station, \
nothing to do return
# Train has arrived at a station, set up for next station
self.stations.pop(0) # eliminate the station at the front of the list
if len(self.stations) == 0:
return # reached the end of the line
run_time_to_next_stoppage = random.randint(2, 6) # whatever time this \
happened plus some random seconds
self.time_at_nextStation = currentTime + run_time_to_next_stoppage # time \
in the future when train gets to next station
self.total_run_time = self.total_run_time + run_time_to_next_stoppage # add \
to total time print('Next stoppage is at', stations[0])
The first time "update" is called, it will move from the 'start' to the first \
station, and calculate when the train should reach the first station. Because update \
is called continuously, it only needs to check if the time for getting to the next \
station has been reached. If so, then set up for the next station.
That way, your main loop becomes:
train.run()
while len(train.stations) is not 0:
train.update()
Then you could have another property to get the total time (and print).
Personally, I would prefer that train.update would return True or False to say if it \
was done with the whole route. that is, it would normally return False to say it is \
not done yet. But when it gets to the end, it would return True. Then your main \
code could be written as:
train.run()
while True:
done = train.update()
if done:
break
Like I said, totally untested, but the idea of splitting into two methods, and \
eliminating the time.sleep is a better approach.
Irv
--
https://mail.python.org/mailman/listinfo/python-list
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic