首先创建两个子线程
def get_target_html():
print("获取目标网址start\n")
time.sleep(2)
print("获取目标网址end\n")
def get_target_url():
print("获取目标URL,start\n")
time.sleep(2)
print("获取目标URL,end\n")
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:{}'.format(threading.current_thread().name))
# 在未指定的情况下,main函数默认为主线程
thread1 = threading.Thread(target=get_target_html, name="html") # 创建子线程1
thread2 = threading.Thread(target=get_target_url, name="url") # 创建子线程2
thread1.start() # 启动子线程1
thread2.start() # 启动子线程2
print('主线程结束了!{}'.format(threading.current_thread().name))
print('一共用时:{}'.format(time.time() - start_time))
运行查看结果为
可以看出主线程在两个子线程运行完成之前就结束了,两个子线程继续执行直至完成。
但有时我们希望所有的子线程都执行完成再结束主线程,此时需要用到join()
def get_target_html():
print("获取目标网址start\n")
time.sleep(2)
print("获取目标网址end\n")
def get_target_url():
print("获取目标URL,start\n")
time.sleep(2)
print("获取目标URL,end\n")
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:{}'.format(threading.current_thread().name))
thread1 = threading.Thread(target=get_target_html, name="html")
thread2 = threading.Thread(target=get_target_url, name="url")
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('主线程结束了!{}'.format(threading.current_thread().name))
print('一共用时:{}'.format(time.time() - start_time))
target.join(),会阻塞其它的线程直至target线程执行完成/抛出异常。
所以运行流程为:main线程启动-->thread1启动--->thread2启动--->thread1与2均阻塞main线程运行-->thread1与2并行运行-->thread1与2运行完毕--->main线程运行结束
可以参考官方解释:
def join(self, timeout=None):
"""Wait until the thread terminates.
This blocks the calling thread until the thread whose join() method is
called terminates -- either normally or through an unhandled exception
or until the optional timeout occurs.
When the timeout argument is present and not None, it should be a
floating point number specifying a timeout for the operation in seconds
(or fractions thereof). As join() always returns None, you must call
is_alive() after join() to decide whether a timeout happened -- if the
thread is still alive, the join() call timed out.
When the timeout argument is not present or None, the operation will
block until the thread terminates.
A thread can be join()ed many times.
join() raises a RuntimeError if an attempt is made to join the current
thread as that would cause a deadlock. It is also an error to join() a
thread before it has been started and attempts to do so raises the same
exception.
此外需要注意的错误,区分赋值操作时带()与不带()的区别
def get_target_html():
print("获取目标网址start\n")
time.sleep(2)
print("获取目标网址end\n")
def get_target_url():
print("获取目标URL,start\n")
time.sleep(2)
print("获取目标URL,end\n")
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:{}'.format(threading.current_thread().name))
thread1 = threading.Thread(target=get_target_html(), name="html")
thread2 = threading.Thread(target=get_target_url(), name="url")
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('主线程结束了!{}'.format(threading.current_thread().name))
print('一共用时:{}'.format(time.time() - start_time))
笔者在第一次写程序时,在调用两个子线程方法时加上了(),类不带括号---赋值,带括号---实例化
因此在执行
thread1 = threading.Thread(target=get_target_html(), name="html")
thread2 = threading.Thread(target=get_target_url(), name="url")
时,target=get_target_html(), target=get_target_url()会自动实例化并执行方法中的语句,无论加不加join()语句,主线程的运行时间一定会≥4s