(Feb-02-2022, 01:35 PM)deanhystad Wrote: The difference between windows and unix is windows spawns a fresh process with all new global variables. This means each process has it's own global hotel[] and nobody adds items to the hotel[] in the parent process. To get around this you do not use global variables, but instead use local variables which are passed as arguments to the child processes.
In unix a process is forked. It starts out as an exact copy of the parent. This means the child processes have the same global variables as the parent processes.
Ok, so I have to be honest. I don't understand python well enough to work with the manager yet, so I tried to use Queue, which actually worked!
Thing is. It only works as long as the number of objects doesn't exceed 584.
Any idea what the reason for this could be? It just stops doing anything when I enter something higher than 584, which is an oddly specific number.
EDIT: Actually, I can reach even higher numbers, but it doesn't always succeed. The runs seem to be more likely to succeed when they are a multiple of 4.
import random import multiprocessing as mp 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 hotel = [] hotel1 = [] 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(q,x): hotel = [] for i in range(x): #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. hotel.append(tenanti) #Puts the tenants into the hotel q.put(hotel) def produceTenants2(): 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. hotel1.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 q = mp.Queue() p1 = mp.Process(target = produceTenants1, args = (q,guestsPerThread)) p2 = mp.Process(target = produceTenants1, args = (q,guestsPerThread)) p3 = mp.Process(target = produceTenants1, args = (q,guestsPerThread)) p4 = mp.Process(target = produceTenants1, args = (q,guestsPerThread)) p1.start() p2.start() p3.start() p4.start() p1.join() hotel = q.get() p2.join() hotel = hotel + q.get() p3.join() hotel = hotel + q.get() p4.join() hotel = hotel + q.get() produceTenants2() hotel = hotel + hotel1 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()