So I wrote this massive code filling a hotel with fictional objects (i.e. people) with a bunch of attributes with random values, then making a statistical analysis of those attributes. Now I'm trying to make it faster.
I've tried it with multithreading, but when I produced 10 000 000 guests, it only made my code 3 seconds faster (45 instead of 48 sec).
So now I'm wondering how I would make this more efficient using multiprocessing. Unfortunately, whatever I tried doesn't work, the processes don't actually do anything. I always get 0 guests.
This is the code with multithreading. I know it's convoluted and there are much more efficient ways to do this, but the point is doing it with objects.
Of course, any other suggestions to make this faster while still using objects would be appreciated as well.
Thanks in advance!
I've tried it with multithreading, but when I produced 10 000 000 guests, it only made my code 3 seconds faster (45 instead of 48 sec).
So now I'm wondering how I would make this more efficient using multiprocessing. Unfortunately, whatever I tried doesn't work, the processes don't actually do anything. I always get 0 guests.
This is the code with multithreading. I know it's convoluted and there are much more efficient ways to do this, but the point is doing it with objects.
Of course, any other suggestions to make this faster while still using objects would be appreciated as well.
Thanks in advance!
import random
import threading
guestsUnderage = 0
guestsUnderageMale = 0
guestsUnderageFemale = 0
guestsAdults = 0
guestsTotal = 0
guestsEurope = 0
guestsAsia = 0
guestsAmericas = 0
guestsAfrica = 0
guestsAustralia = 0
numberPredominantOrigins = 0
number_of_guests = 0
guestsPerThread = 0
guestsFraction = 0
hotel1= []
hotel2 = []
hotel = []
origins = ['Europe', 'Africa', 'The Americas', 'Asia', 'Australia'] #List of possible origins. I have not yet used this attribute for anything in the statistics.
ages = range(10,70) #List of possible ages. This is a list of integers!!! Hence, it might need to be changed into a string depending on the situation it is to be used in. (see line 25)
genders = ['male', 'female']
class Tenant: #Definies what attributes the tenant (i.e. object) will have
roomNumberCount = 1
__slots__ = ['roomNumber', 'origin', 'age', 'gender']
def __init__(self, roomNumber, origin, age, gender):
self.roomNumber = roomNumber
self.origin = origin #String with origin name
self.age = age #This will be a string! Hence it might need to be changed into an integer depending on the situation. (see line 31)
self.gender = gender
Tenant.roomNumberCount += 1
def __str__(self): #Structure of the output when calling upon a tenant (i.e. object)
return f'\nRoom Number: {str(self.roomNumber)} \nOrigin: {self.origin} \nAge: {str(self.age)} \nGender: {self.gender}'
def produceTenants1():
global hotel1
for i in range(guestsPerThread): #Random number of rooms between 20 and 40
tenanti = Tenant(str(Tenant.roomNumberCount),origins[random.randint(0, len(origins) - 1)], str(ages[random.randint(0, len(ages) - 1)]), genders[random.randint(0, len(genders)-1)]) #Tells python the object class (i.e. Tenant) and where to get the attribute information from. In this case each attribute's value was chosen at random from the selection above. The first list point in the list is 0!!!, so we have to subtract 1 from the total length of each list, otherwise it might chose an option outside the range which would give us an error.
hotel1.append(tenanti) #Puts the tenants into the hotel
def produceTenants2():
global hotel2
for i in range(guestsFraction): #Random number of rooms between 20 and 40
tenanti = Tenant(str(Tenant.roomNumberCount),origins[random.randint(0, len(origins) - 1)], str(ages[random.randint(0, len(ages) - 1)]), genders[random.randint(0, len(genders)-1)]) #Tells python the object class (i.e. Tenant) and where to get the attribute information from. In this case each attribute's value was chosen at random from the selection above. The first list point in the list is 0!!!, so we have to subtract 1 from the total length of each list, otherwise it might chose an option outside the range which would give us an error.
hotel2.append(tenanti) #Puts the tenants into the hotel
def main():
global number_of_guests, guestsPerThread, guestsFraction
try: # Number of guests determined by user input
number_of_guests = int(input("How many people have checked in?"))
except Exception as exception: # If number is not integer
number_of_guests = 100
if (type(exception).__name__) == 'ValueError':
print('Entered value has to be integer! Setting number to default value (>>100<< guests).')
else:
print(f'{type(exception).__name__}! Setting number to default value (>>100<< guests).')
guestsPerThread = number_of_guests // 4
guestsFraction = number_of_guests % 4
t1 = threading.Thread(target = produceTenants1)
t2 = threading.Thread(target = produceTenants1)
t3 = threading.Thread(target = produceTenants1)
t4 = threading.Thread(target = produceTenants1)
t1.start()
t2.start()
t3.start()
t4.start()
t1.join()
t2.join()
t3.join()
t4.join()
produceTenants2() #Producing the remaining fraction
hotel = hotel1 + hotel2
global guestsTotal, guestsUnderage, guestsUnderageFemale, guestsUnderageMale, guestsAdults, guestsEurope, guestsAfrica, guestsAsia, guestsAmericas, guestsAustralia, numberPredominantOrigins
for guest in hotel: #guest is used to differentiate from Tenant and tenanti. Could have been used interchangably, though.
guestsTotal += 1
origin = guest.origin
if int(guest.age) < 18:
guestsUnderage += 1
if guest.gender == 'male':
guestsUnderageMale += 1
else:
guestsUnderageFemale += 1
else:
guestsAdults += 1
match origin:
case 'Europe':
guestsEurope += 1
case 'Africa':
guestsAfrica += 1
case 'Asia':
guestsAsia += 1
case 'The Americas':
guestsAmericas += 1
case 'Australia':
guestsAustralia += 1
for guest in hotel:
if int(guest.roomNumber) <= 5: # This is just to verify that the room numbers are successive
print(guest)
else:
break
originDictionary = {'Europe': guestsEurope, 'Africa': guestsAfrica, 'Asia': guestsAsia, 'The Americas': guestsAmericas, 'Australia': guestsAustralia}
guestsFromPredominantOrigin = originDictionary.get(max(originDictionary, key=originDictionary.get)) # String associated with the largest value in the dictionary. Still haven't figured out what to do if there are two equal values at the top.
predominantOrigin = []
for k, v in originDictionary.items():
if v == guestsFromPredominantOrigin:
predominantOrigin.append(k)
numberPredominantOrigins += 1 # I will change the list below so I need this separate counter at the end
delimiter = ' or '
if len(predominantOrigin) == 1:
predominantOrigin = delimiter.join(predominantOrigin)
else:
predominantOrigin = delimiter.join([", ".join(predominantOrigin[:-1]),predominantOrigin[-1]])
print(f'{guestsTotal} guests have checked into the hotel. {guestsUnderage} were underage and among those, {guestsUnderageFemale} were female and {guestsUnderageMale} were male. Most people came from {predominantOrigin}, numbering {guestsFromPredominantOrigin}' + ('.' if numberPredominantOrigins == 1 else ' each.'))
if __name__ == "__main__":
main()
