import os, gc, sys, time, random import threading import platform concurentThreads = threading.Semaphore(1500) # limit simultaneous threads class ThreadSafeGlobalDataContainer: __container = {} __lock = threading.Lock() @classmethod def set(cls, name, value): with cls.__lock: cls.__container[name] = value @classmethod def get(cls, name): with cls.__lock: return cls.__container.get(name, None) def DoSomething(): time.sleep(random.random() * 0.5) # [0.0,1.0) return random.randint(7,7777), concurentThreads.release() def GetFullObjName(obj): module = obj.__class__.__module__ if module is None or module == str.__class__.__module__: return obj.__class__.__name__ return module + '.' + obj.__class__.__name__ def GetFullClassName(obj): module = obj.__module__ if module is None or module == str.__module__: return obj.__name__ return module + '.' + obj.__name__ def FormatTimeout(timeout, smart=True, empty=True): # as float seconds fmt = ''; data = [] years, remains = divmod(timeout, 24 * 3600 * 365) if years: fmt += "{:.0f}y:"; data += [years] days, remains = divmod(remains, 24 * 3600) if days or (fmt and empty): fmt += "{:.0f}d:" if fmt else "{:.0f}d:"; data += [days] hours, remains = divmod(remains, 3600) if hours or (fmt and empty): fmt += "{:02.0f}h:" if fmt else "{:.0f}h:"; data += [hours] minutes, seconds = divmod(remains, 60) if minutes or (fmt and empty): fmt += "{:02.0f}m:" if fmt else "{:.0f}m:"; data += [minutes] fmt += "{:05.2f}s" if fmt else "{:.2f}s" data += [seconds] if smart: return fmt.format(*data) return "{:.0f}d:{:02.0f}h:{:02.0f}m:{:05.2f}s".format(days + years * 365, hours, minutes, seconds) if __name__ == "__main__": start = time.time() elapsed = start count = 0 #threading.stack_size(128*1024) # maximize available threads isdaemon = False #if platform.system() == 'Windows' else True # bad case ##isdaemon = not isdaemon # good case islambda = True # doesn't matter isdelete = False # doesn't matter print("Testing on:", platform.system(), platform.machine()) print("Testing with= daemons:", isdaemon, "delete:", isdelete, "lambdas:", islambda) def SimpleSet(): return ThreadSafeGlobalDataContainer.set('smth', DoSomething()) def SimpleGet(count): return print(threading.active_count(), ThreadSafeGlobalDataContainer.get('smth')[0], count, '\t\t', end='\r', flush=True) try: while True: concurentThreads.acquire() if islambda: thread = threading.Thread(target=lambda: ThreadSafeGlobalDataContainer.set('smth', DoSomething()), args=(), daemon=isdaemon) thread.start() if isdelete: del thread else: thread = threading.Thread(target=SimpleSet, args=(), daemon=isdaemon) thread.start() if isdelete: del thread count += 1 if time.time() - elapsed > 1.3: if islambda: threading.Thread(target=lambda: print(threading.active_count(), ThreadSafeGlobalDataContainer.get('smth')[0], count, '\t\t', end='\r', flush=True), args=(), daemon=not isdaemon).start() else: threading.Thread(target=SimpleGet, args=(count), daemon=isdaemon).start() elapsed = time.time() if isdelete: gc.collect() except: exc_type, value, traceback = sys.exc_info() print('\n\nReason:', GetFullClassName(exc_type), value) print(threading.active_count(), ThreadSafeGlobalDataContainer.get('smth')[0]) finally: start = time.time() - start print("\ntotal {} for {} avg/sec={:.2f}".format(count, FormatTimeout(start), count / start)) print('leaks:', ', '.join(map('{}'.format, gc.garbage)))