python多线程简单操作
python的线程类似于java 的线程,也区分守护线程和非守护线程。守护线程的作用就是为其他线程的运行提供便利。
默认是非守护线程。当进程所有的非守护结束后,进程会自动结束。
1. 线程简单使用
1. 直接new Thread 的方式
# 线程使用的方式一
import threading
# 需要多线程运行的函数
import time
def doPrint(param):
current = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
print(current + "\t" + str(param))
def fun(args):
doPrint("线程开始, name: {}, args: {}".format(threading.current_thread().getName(), args))
doPrint("thread is Daemon: " + str(threading.current_thread().isDaemon()))
time.sleep(3)
doPrint("线程结束, name: {}, args: {}".format(threading.current_thread().getName(), args))
if __name__ == '__main__':
# 打印当前main 线程的信息
doPrint(threading.current_thread().getName())
doPrint(threading.current_thread().__class__)
# 创建一个线程并且开始一个新的线程。 两个参数就可以。
t1 = threading.Thread(target=fun, args=(1,))
# t1 = threading.Thread(target=fun, name='t1', args=(1,), daemon=True)
t1.start()
time.sleep(1)
doPrint("main thread end ")
结果: (可以看出默认的线程规则是 Thread-{num})
20220729174638 MainThread
20220729174638 <class 'threading._MainThread'>
20220729174638 线程开始, name: Thread-1, args: 1
20220729174638 thread is Daemon: False
20220729174639 main thread end
20220729174641 线程结束, name: Thread-1, args: 1
改成第二种指定name,并且设置为守护线程查看日志如下:
20220729174843 MainThread
20220729174843 <class 'threading._MainThread'>
20220729174843 线程开始, name: t1, args: 1
20220729174843 thread is Daemon: True
20220729174844 main thread end
2. 继承的方式
import threading
import time
def doPrint(param):
current = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
print(current + "\t" + str(param))
class MyThreading(threading.Thread):
def __init__(self, name):
super(MyThreading, self).__init__()
self.name = name
# 线程要运行的代码
def run(self):
doPrint("线程开始, name: {}".format(threading.current_thread().getName()))
doPrint("thread is Daemon: " + str(threading.current_thread().isDaemon()))
time.sleep(3)
doPrint("线程结束, name: {}".format(threading.current_thread().getName()))
if __name__ == '__main__':
# 打印当前main 线程的信息
doPrint(threading.current_thread().getName())
doPrint(threading.current_thread().__class__)
# 创建一个线程并且开始一个新的线程。 两个参数就可以。
# t1 = threading.Thread(target=fun, args=(1,))
t1 = MyThreading("cus-1")
t1.start()
time.sleep(1)
doPrint("main thread end ")
结果:
20220729175358 MainThread
20220729175358 <class 'threading._MainThread'>
20220729175358 线程开始, name: cus-1
20220729175358 thread is Daemon: False
20220729175359 main thread end
20220729175401 线程结束, name: cus-1
3. 源码查看
- Thread 构造方法 threading.Thread.init
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
"""This constructor should always be called with keyword arguments. Arguments are:
*group* should be None; reserved for future extension when a ThreadGroup
class is implemented.
*target* is the callable object to be invoked by the run()
method. Defaults to None, meaning nothing is called.
*name* is the thread name. By default, a unique name is constructed of
the form "Thread-N" where N is a small decimal number.
*args* is the argument tuple for the target invocation. Defaults to ().
*kwargs* is a dictionary of keyword arguments for the target
invocation. Defaults to {}.
If a subclass overrides the constructor, it must make sure to invoke
the base class constructor (Thread.__init__()) before doing anything
else to the thread.
"""
assert group is None, "group argument must be None for now"
if kwargs is None:
kwargs = {}
self._target = target
self._name = str(name or _newname())
self._args = args
self._kwargs = kwargs
if daemon is not None:
self._daemonic = daemon
else:
self._daemonic = current_thread().daemon
self._ident = None
if _HAVE_THREAD_NATIVE_ID:
self._native_id = None
self._tstate_lock = None
self._started = Event()
self._is_stopped = False
self._initialized = True
# Copy of sys.stderr used by self._invoke_excepthook()
self._stderr = _sys.stderr
self._invoke_excepthook = _make_invoke_excepthook()
# For debugging and _after_fork()
_dangling.add(self)
threading.Thread.run 线程默认的run 方法:
def run(self):
"""Method representing the thread's activity.
You may override this method in a subclass. The standard run() method
invokes the callable object passed to the object's constructor as the
target argument, if any, with sequential and keyword arguments taken
from the args and kwargs arguments, respectively.
"""
try:
if self._target:
self._target(*self._args, **self._kwargs)
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self._target, self._args, self._kwargs
可以看出, 如果传了target 参数,会调用方法,传入的参数就是自身的两个属性 _args(tuple 元组类型) 和 _kwargs(dict类型)
2. 线程相关方法
1. join 变成同步
# 线程使用的方式一
import threading
# 需要多线程运行的函数
import time
def doPrint(param):
current = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
print(current + "\t" + str(param))
def fun(args):
doPrint("线程开始, name: {}, args: {}".format(threading.current_thread().getName(), args))
doPrint("thread is Daemon: " + str(threading.current_thread().isDaemon()))
time.sleep(3)
doPrint("线程结束, name: {}, args: {}".format(threading.current_thread().getName(), args))
if __name__ == '__main__':
# 打印当前main 线程的信息
doPrint(threading.current_thread().getName())
doPrint(threading.current_thread().__class__)
# 创建一个线程并且开始一个新的线程。 两个参数就可以。
t1 = threading.Thread(target=fun, args=(1,))
t1.start()
# join 方法相当于当前线程等待join 的方法完成,类似于同步的效果。 可以传一个timeout 参数,指定超时时间
t1.join()
time.sleep(1)
doPrint("main thread end ")
结果:
20220729180843 MainThread
20220729180843 <class 'threading._MainThread'>
20220729180843 线程开始, name: Thread-1, args: 1
20220729180843 thread is Daemon: False
20220729180846 线程结束, name: Thread-1, args: 1
20220729180847 main thread end
2. 线程池使用
import random
import threading
import time
from concurrent.futures import ThreadPoolExecutor
def doPrint(param):
current = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
print(current + "\t" + threading.current_thread().getName() + "\t" + str(param))
def task(video_url):
doPrint("开始执行任务" + video_url)
time.sleep(1)
# 将结果封装成一个Futuer对象,返回给线程池
return random.randint(0, 10)
# response就是futuer对象,也就是task的返回值分装的一个Futuer对象
def done(response):
# 即Futuer.result():取出task的返回值
doPrint("任务执行完后,回调的函数" + str(response.result()))
# 创建线程池
threadpool = ThreadPoolExecutor(10)
url_list = ["www.xxxx-{}.com".format(i) for i in range(5)]
for url in url_list:
# futuer是由task返回的一个Future对象,里面有记录task的返回值
futuer = threadpool.submit(task, url)
# 回调done函数,执行者依然是子线程
futuer.add_done_callback(done)
doPrint("等待线程池中的任务执行完毕中······")
threadpool.shutdown(True) # 等待线程池中的任务执行完毕后,在继续执行
doPrint("END")
结果:
20220729205033 ThreadPoolExecutor-0_0 开始执行任务www.xxxx-0.com
20220729205033 ThreadPoolExecutor-0_1 开始执行任务www.xxxx-1.com
20220729205033 ThreadPoolExecutor-0_2 开始执行任务www.xxxx-2.com
20220729205033 ThreadPoolExecutor-0_3 开始执行任务www.xxxx-3.com
20220729205033 ThreadPoolExecutor-0_4 开始执行任务www.xxxx-4.com20220729205033 MainThread 等待线程池中的任务执行完毕中······
20220729205034 ThreadPoolExecutor-0_0 任务执行完后,回调的函数3
20220729205034 ThreadPoolExecutor-0_1 任务执行完后,回调的函数9
20220729205034 ThreadPoolExecutor-0_4 任务执行完后,回调的函数6
20220729205034 ThreadPoolExecutor-0_2 任务执行完后,回调的函数3
20220729205034 ThreadPoolExecutor-0_3 任务执行完后,回调的函数3
20220729205034 MainThread END
【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】
分类:
python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2019-07-30 模板方法(TemplateMethod)模式
2018-07-30 struts2 中 Preparable 接口实现数据准备
2017-07-30 Spring使用注解和struts集成
2017-07-30 404错误处理以及以后缀为action结尾的处理
2017-07-30 Struts局部异常与全局异常处理