python的join和daemon
其他基本概念
# 进程,线程,协程 # 串行,并行,并发 # 同步/异步 阻塞/非阻塞 # # # python 的多线程败笔: # 多进程可以并行,然而由于GIL锁的缘故,导致同一时刻,同一进程,只能有一个线程运行。 # 多线程不可进行并行。 # # 并行是最快的,并发速度稍微慢点 # join:主线程开始,等待当前子线程完成,才结束主线程 # daemon守护线程:跟随主线程,主线程结束,子线程直接结束,步调和主线程保持一致
基本例子
#!/usr/bin/env python # -*- encoding: utf-8 -*- """ """ from ycyj_zhongtai.apis_gongshi.free_fast_search.ffs_base import dzh_data_req # from ycyj_zhongtai.service_ref.dzh_hqdata import DzhF10Api # obj = DzhF10Api() # res = obj.get_f10_十大股东('300546.SZ') # print(res) # # for item in res: # print(item) # 生成大智慧token token = dzh_data_req.get_dzh_token() # url = 'http://gw.yundzh.com/f10/cwts/lrfpbzy?field=jlr&start=-6&count=6&obj=600171.SH&Obj=SZ300928&token={}'.format(token) # print(url) # # url = 'http://gw.yundzh.com/f10/gdjc/sdgd?field=Zjqk&start=-1&count=1&token={}&obj={}'.format(token, 'SZ300478') # print(url) # # url = 'http://gw.yundzh.com/f10/cwts/zycwzb?field=xsmll&start=-1&count=1&token={}&obj={}'.format(token, 'SH600519') # print(url) # 净资产收益率 # url = 'http://gw.yundzh.com/f10/cpbd/zxzb?field=jzcsyl,zylrtbzz,jlrtbzz&start=-1&count=1&token={}&obj={}'.format(token, 'SZ300088') # print(url) import logging import time import threading logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s] %(message)s') def worker1): logging.info('starting1') time.sleep(13) logging.info('stopping1') def worker2(): logging.info('starting2') time.sleep(1) logging.info('stopping2') if __name__ == '__main__': logging.info('0') t1 = threading.Thread(target=worker1, name='worker1', daemon=False) t1.start() time.sleep(1) t2 = threading.Thread(target=worker2, name='worker2', daemon=True) t2.start() logging.info('1')
一般默认子线程setDaemon(False),这样主线程和子线程各干各的,都执行完毕结束 子线程setDaemon(True),这样主线程完毕,不管子线程有没有结束,直接杀掉结束 join,主线程会等子线程全部结束,才结束 业务场景需要主线程等子线程执行完毕结束的用join 业务场景需要各自执行完毕的,什么也不干涉,什么也不用写 业务场景只需要主线程干活,子线程无所谓的,设置守护线程,但是感觉好像没什么意义 # 计算密集型:大量使用cpu且占据,python多线程不好使 # IO密集型:存在大量IO操作,python多线程好使 # python 使用多核: # 用进程弊端:开销大,切换复杂 # 解决方案:协程 本质上是单线程 # 方向:IO多路复用 # 终极思路:换C模块实现多线程 # (1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。 # (2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。 # (3)CPU分给线程,即真正在CPU上运行的是线程。 # 并行处理(Parallel Processing)是计算机系统中能同时执行两个或更多个处理的一种计算方法。 # 并行处理可同时工作于同一程序的不同方面。 # 并行处理的主要目的是节省大型和复杂问题的解决时间。 # 并发处理(concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间, # 且这几个程序都是在同一个处理机(CPU)上运行,但任一个时刻点上只有一个程序在处理机(CPU)上运行 # 并发的关键是你有处理多个任务的能力,不一定要同时。 # 并行的关键是你有同时处理多个任务的能力。所以说,并行是并发的子集
join和daemon的基本使用举例:
# join:等待当前线程完成,才执行主线程(取决于子线程)
# daemon守护线程:跟随主线程,主线程结束,子线程直接结束,步调和主线程保持一致(取决于主线程)
# join():在子线程完成运行之前,这个子线程的父线程将一直被阻塞。 # 换句话解释:要等绑定这个方法的对象执行完毕才可以执行主线程。 # setDaemon(True): ''' 将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。 当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行。 那么当主线程完成,想退出时,会检验子线程是否完成。 如果子线程未完成,则主线程会等待子线程完成后再退出。 但是有时候我们需要的是只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法 ''' import threading from time import ctime,sleep import time def Music(name): print ("Begin listening to {name}. {time}".format(name=name,time=ctime())) sleep(3) print("end listening {time}".format(time=ctime())) def Blog(title): print ("Begin recording the {title}. {time}".format(title=title,time=ctime())) sleep(5) print('end recording {time}'.format(time=ctime())) threads = [] t1 = threading.Thread(target=Music,args=('FILL ME',)) t2 = threading.Thread(target=Blog,args=('',)) threads.append(t1) threads.append(t2) if __name__ == '__main__': #t2.setDaemon(True) for t in threads: #t.setDaemon(True) #注意:一定在start之前设置 t.start() t.join() #等价于必须某程序结束以后才能执行主程序 #t1.join() #阻塞主线程,等t1结束,然后进行主线程 #t2.join() # 考虑这三种join位置下的结果? print ("all over %s" %ctime())
# -*- coding:utf-8 -*- import threading import time def run(): time.sleep(2) print('当前线程的名字是: ', threading.current_thread().name) time.sleep(2) if __name__ == '__main__': start_time = time.time() print('这是主线程:', threading.current_thread().name) thread_list = [] for i in range(5): t = threading.Thread(target=run) thread_list.append(t) for t in thread_list: t.setDaemon(True) t.start() # t.join() print('一共用时:', time.time() - start_time) print('主线程结束!' , threading.current_thread().name)