def insert_song_info(self, ): logging.info(u'%s process runing pid:%s' % (sys._getframe().f_code.co_name, os.getpid())) print u'%s process runing pid:%s' % (sys._getframe().f_code.co_name, os.getpid()) while True: try: d = self.song_info_queue.get(block=True, timeout=30) msi = Multi_Song_Info(d['ids'], d['refer'], self.mysql) self.thread_pool.submit(msi.insert_song) logging.info( u'%s start new threading, get song ids=%s,threading name is:%s,pid is:%s' % (sys._getframe().f_code.co_name, d['ids'], threading.current_thread().name, os.getpid())) except Exception, e: if str(e): e = str(e) else: ##queue raise error e , str(e)为空 e = 'queue empty' logging.warn( u' function %s raise error cause by %s,traceback info is:%s ' % (sys._getframe().f_code.co_name, e, traceback.format_exc())) print e break
def test():##用于测试网络环境 info=u'runing %s to test avg_time'%(sys._getframe().f_code.co_name) print info logging.info(info) multiple=g_multiple count=0 t1=time.time() results=[] times=[] while True: logging.info(u'wait 100 second try to get element from queue') d=song_info_queue.get(timeout=100) logging.info(u'get %s from queue'%d) msi=Multi_Song_Info(song_ids=d['ids'],refer=d['refer']) result=pool.submit(msi.insert_song)## # song_info_queue.put(d)## 不需要放回去了,因为已经更新了!! results.append(result) logging.info(u'%s start new threading, get song ids=%s,threading name is:%s,pid is:%s'%(sys._getframe().f_code.co_name,d['ids'],threading.current_thread().name,os.getpid())) count+=1 if count>=max_pool*multiple: print u'generate 60 threading to test avg_time' for i in results: t=i.result()##该方法是阻塞的 times.append(t) t2=time.time() print u'test cost time:%s'%(t2-t1) # return times,t2-t1 print u'test finish!' return sum(times)/len(times)
def run(): count = 0 multiple = 3 while True: try: logging.info(u'wait 100 second try to get element from queue') d = song_info_queue.get(timeout=100) logging.info(u'get %s from queue' % d) # mysql=Cloud_Music_MySQL() ''' 不使用连接池技术可能会造成mysql连接开销过大,如果对产生的线程数不加限制的话,使用此方法从queue中读取到的数据接近于mysql的max_connections, 不使用数据库连接池会导致mysql status中thread数暴涨,很快到达瓶颈(网络不好的情况下??) ''' # mysql=Cloud_Music_MySQL_Pool() ##使用数据库连接池和不使用目前还没有看出差别 msi = Multi_Song_Info(song_ids=d['ids'], refer=d['refer']) pool.submit(msi.insert_song) ## # mysql.close() #不能在此关闭数据库连接,因为主线程非阻塞,子线程数据库相关任务还没有完成,主线程就把数据库连接给关闭了 logging.info( u'%s start new threading, get song ids=%s,threading name is:%s,pid is:%s' % (sys._getframe().f_code.co_name, d['ids'], threading.current_thread().name, os.getpid())) count += 1 if count > max_pool * multiple: ##大于一定值线程数需要等待线程处理,不要回报too many connections。程序线程数大于22,一般在46或是67左右,可能是由于一个线程在 ##运行结束后没有关闭数据库连接,一定时间内,系统还为其保留数据库连接,导致线程处于闲置状态。(因为其没有任务可以接受)。 print u'generate 60 threading,so sleep 20 second! current active threading num=%s' % threading.active_count( ) sleeptime = multiple * 6 time.sleep(sleeptime) count = 0 ''' 系统每创建60个线程就会休息60s,因为线程池的大小为21个,所以同时会运行21个线程,假如每个线程运行时间差不多,每个线程运行时间需要平均3s, 那么大概9秒的时间,60个线程就会全部运行完毕。所以大概等待9秒左右,能够最大程度的利用系统资源。避免了过多等待时间。 sleeptime=count最大值/线程池大小*平均每个线程运行时间(sleeptime=60/21*3=9) 网络环境良好的环境下,数据库线程数很小(宿舍测试max_pool=11,count=22,timesleep=20的情况下,数据库线程数稳定在22) 网络良好的情况下,sleeptime=30,max_count=60,max_pool=21时,mysql status线程数稳定在30-70左右。(在) 网络良好的情况下,sleeptime=10,max_count=60,max_pool=21时,mysql status线程数越跑越多。运行5分钟后,线程会跑到500左右 线程平均运行时间最大的影响因素在于网络流畅程度。网络状态良好的话,sleeptime设置20是没问题的。 如果主线程不sleep的话,创建很多等待的线程,这些线程不能利用到连接池的优势,即一个数据库连接可以被不同的线程利用多次。 因为数据库连接池中的每一个连接都被等待中的线程占用了。 ''' except Exception, e: if str(e): e = str(e) else: ##queue raise error e , str(e)为空 e = 'queue empty' logging.warn( u' function %s raise error cause by %s,traceback info is:%s ' % (sys._getframe().f_code.co_name, e, traceback.format_exc())) print u'error info is:%s' % e if 'many connections' in e: ##最好使用joinablequeue print u'current too many connections,sleep 3 second wait runing connections close' song_info_queue.put(d) print u'catch too many connections error ,so put d=%s back into queue' % d logging.info( u'catch too many connections error ,so put d=%s back into queue' % d) ##发生异常在于数据库操作,d的值可以获取到,所以把他重新放回queue中,所以不需要joinablequeue了 time.sleep(3) continue else: print u'empty queue or other unknown error,so break loop!' print u'wait 20 second ensure runing threading done' time.sleep(20) break
def func(d): msi = Multi_Song_Info(song_ids=d['ids'], refer=d['refer']) return msi.insert_song( ) #传递结果,不能传递函数对象,不加括号,表示返回的是函数对象,需要真正调用msi.insert_song需要以func(d=d)()的形式调用
def run(): '''主函数''' avg_time=test()##平均一个线程花费的时间 logging.info(u'from function test get avg_time=%s'%avg_time) print u'from function test get avg_time=%s'%avg_time count=0 start_time=time.time() multiple=g_multiple while True: try: logging.info(u'max wait 100 second try to get element from queue') d=song_info_queue.get(timeout=100) logging.info(u'get %s from queue'%d) msi=Multi_Song_Info(song_ids=d['ids'],refer=d['refer']) pool.submit(msi.insert_song) logging.info(u'%s start new threading, get song ids=%s,threading name is:%s,pid is:%s'%(sys._getframe().f_code.co_name,d['ids'],threading.current_thread().name,os.getpid())) count+=1 if count>=max_pool*multiple: sleeptime=multiple*avg_time print u'generate 60 threading,so sleep %s second! current active threading num=%s'%(sleeptime,threading.active_count()) time.sleep(sleeptime) count=0 end_time=time.time() if end_time - start_time>=600:##每过10十分做一次检测,确保数据库连接数最好介于30到150之间,保证程序稳定运行 mysql=Cloud_Music_MySQL() Threads_connected=mysql.show_Threads_connected() mysql.close_connect() if Threads_connected<=30: ##说明程序运行效率不高,可以适当提高multiple,或是降低avg_time avg_time=test() multiple=multiple+1 info=u'程序闲置过多,current Threads_connected=%s,重设avg_time=%s,multiple=%s'%(Threads_connected,avg_time,multiple) print info logging.info(info) elif Threads_connected>=150: ##说明程序负荷过重,可以适当降低multiple,或是提高avg_time avg_time=test() multiple=max(multiple-1,2)##multiple最小为2 info=u'程序负荷过重,current Threads_connected=%s,重设avg_time=%s,multiple=%s'%(Threads_connected,avg_time,multiple) print info logging.info(info) else: info=u'程序运行良好,current Threads_connected=%s,保持avg_time=%s,multiple=%s'%(Threads_connected,avg_time,multiple) print info logging.info(info) start_time=time.time()##重设start_time except Exception,e: if str(e): e=str(e) else:##queue raise error e , str(e)为空 e='queue empty' logging.warn(u' function %s raise error cause by %s,traceback info is:%s '%(sys._getframe().f_code.co_name,e,traceback.format_exc())) print u'error info is:%s'%e if 'many connections' in e:##最好使用joinablequeue,##经过600秒一次的性能检测,很难抛出too many connections 异常了 print u'current too many connections,sleep 3 second wait runing connections close' song_info_queue.put(d) print u'catch too many connections error ,so put d=%s back into queue'%d logging.info(u'catch too many connections error ,so put d=%s back into queue'%d) ##发生异常在于数据库操作,d的值可以获取到,所以把他重新放回queue中,所以不需要joinablequeue了 mysql=Cloud_Music_MySQL() Threads_connected=mysql.show_Threads_connected() while Threads_connected>=100: info=u'current Threads_connected is:%s,also too much,so sleep 3 second!'%Threads_connected print info logging.debug(info) time.sleep(3) Threads_connected=mysql.show_Threads_connected() mysql.close_connect() continue elif 'empty' in e: print u'empty queue,break loop!' print u'wait 20 second ensure runing threading done' time.sleep(20) break else: info=u'unexcept error,here is traceback info:%s'%(traceback.format_exc()) print info logging.error(info) song_info_queue.put(d) print u'catch unexcept error ,so put d=%s back into queue'%d break
def run(): avg_time=test()##平均一个线程花费的时间 logging.info(u'from function test get avg_time=%s'%avg_time) print u'u'from function test get avg_time=%s'%avg_time' count=0 while True: try: logging.info(u'max wait 100 second try to get element from queue') d=song_info_queue.get(timeout=100) logging.info(u'get %s from queue'%d) msi=Multi_Song_Info(song_ids=d['ids'],refer=d['refer']) pool.submit(msi.insert_song) logging.info(u'%s start new threading, get song ids=%s,threading name is:%s,pid is:%s'%(sys._getframe().f_code.co_name,d['ids'],threading.current_thread().name,os.getpid())) count+=1 if count>=max_pool*multiple: sleeptime=multiple*avg_time print u'generate 60 threading,so sleep %s second! current active threading num=%s'%(sleeptime,threading.active_count()) time.sleep(sleeptime) count=0 ''' 系统每创建60个线程就会休息60s,因为线程池的大小为21个,所以同时会运行21个线程,假如每个线程运行时间差不多,每个线程运行时间需要平均3s, 那么大概9秒的时间,60个线程就会全部运行完毕。所以大概等待9秒左右,能够最大程度的利用系统资源。避免了过多等待时间。 sleeptime=count最大值/线程池大小*平均每个线程运行时间(sleeptime=60/21*3=9) 网络环境良好的环境下,数据库线程数很小(宿舍测试max_pool=11,count=22,timesleep=20的情况下,数据库线程数稳定在22) 网络良好的情况下,sleeptime=30,max_count=60,max_pool=21时,mysql status线程数稳定在30-70左右。(在) 网络良好的情况下,sleeptime=10,max_count=60,max_pool=21时,mysql status线程数越跑越多。运行5分钟后,线程会跑到500左右 线程平均运行时间最大的影响因素在于网络流畅程度。网络状态良好的话,sleeptime设置20是没问题的。 如果主线程不sleep的话,创建很多等待的线程,这些线程不能利用到连接池的优势,即一个数据库连接可以被不同的线程利用多次。 因为数据库连接池中的每一个连接都被等待中的线程占用了。 ''' except Exception,e: if str(e): e=str(e) else:##queue raise error e , str(e)为空 e='queue empty' logging.warn(u' function %s raise error cause by %s,traceback info is:%s '%(sys._getframe().f_code.co_name,e,traceback.format_exc())) print u'error info is:%s'%e if 'many connections' in e:##最好使用joinablequeue print u'current too many connections,sleep 3 second wait runing connections close' song_info_queue.put(d) print u'catch too many connections error ,so put d=%s back into queue'%d logging.info(u'catch too many connections error ,so put d=%s back into queue'%d) ##发生异常在于数据库操作,d的值可以获取到,所以把他重新放回queue中,所以不需要joinablequeue了 time.sleep(3) continue else: print u'empty queue or other unknown error,so break loop!' print u'wait 20 second ensure runing threading done' time.sleep(20) break