python线程中的args代表什么含义_带你了解Python多线程的
基础概念!
多线程基础概念
并⾏与并发
并⾏:同时处理多个任务,必须在多核环境下
⼀段时间内同时处理多个任务,单核也可以并发
并发⼿段
线程:内核空间的调度
进程:内核空间的调度
协程:⽤户空间的调度
线程可以允许程序在同⼀进程空间中并发运⾏多个操作。本次主要介绍Python标准库中的多线程模块threading。
threading模块
线程初始化
使⽤threading模块的Thread类初始化对象然后调⽤start⽅法启动线程。
import threading
import time
def worker(num):
time.sleep(1)
print('worker-{}'.format(num))
# 创建线程对象 target参数是⼀个函数, 这个函数即线程要执⾏的逻辑
threads = [threading.Thread(target=worker, args=(i, ))for i in range(5)]
for t in threads:
t.start()
# start ⽅法启动⼀个线程, 当这个线程的逻辑执⾏完毕的时候,线程⾃动退出, Python 没有提供主动退出线程的⽅法
# 输出以下结果
worker-0worker-1worker-2worker-3
worker-4
初始化的五个线程的执⾏逻辑中的print⽅法打印字符串及换⾏符出现了随机分布,即出现了资源竞争。
给线程传递参数
import threading
import time
def worker(*args, **kwargs):
time.sleep(1)
print(kwargs)
threads = threading.Thread(target=worker, args=(1, 2, 3), kwargs={'a':'b'}).start()
# 输出
(1, 2, 3)
{'a': 'b'}
args传递位置参数,kwargs传递关键字参数。
Thread常⽤参数和⽅法
>>> help(threading.Thread)
可以看到Thread函数的初始化⽅法中的参数如下:
| __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 {}.
name
表⽰线程名称,默认情况下,线程名称是 Thread-N ,N是⼀个较⼩的⼗进制数。我们可以传递name参数,控制线程名称。以下会导⼊logging模块来显⽰线程的名称等详细信息
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s] %(message)s') def worker(num):
logging.info('worker-{}'.format(num))
threads = [threading.Thread(target=worker, args=(i, ), name='workerthread-{}'.format(i)) for i in range(5)]
for t in threads:
t.start()
# 输出
2017-03-20 21:39:29,339 INFO [workerthread-0] worker-0
2017-03-20 21:39:29,340 INFO [workerthread-1] worker-1
2017-03-20 21:39:29,340 INFO [workerthread-2] worker-2
2017-03-20 21:39:29,340 INFO [workerthread-3] worker-3
2017-03-20 21:39:29,346 INFO [workerthread-4] worker-4
其中logging模块的basicConfig函数的format中的%(threadName)s就是⽤来输出当前线程的名称的。
线程可以重名, 线程名并不是线程的唯⼀标识,但是通常应该避免线程重名,通常的处理⼿段是加前缀
daemon
Daemon:守护
和Daemon线程相对应的还有Non-Daemon线程,在此Thread初始化函数中的daemon参数即表⽰线程是否是Daemon线程。Daemon线程:会伴随主线程结束⽽结束(可以理解为主线程结束,守护线程结束)
Non-Daemon线程:不会随着主线程结束⽽结束,主线程需要等待Non-Daemon结束
import logging
import time
import threading
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s] %(message)s') def worker():
logging.info('starting')
time.sleep(2)
logging.info('stopping')
if __name__ == '__main__':
logging.info('starting')
t1 = threading.Thread(target=worker, name='worker1', daemon=False)
t1.start()
time.sleep(1)
t2 = threading.Thread(target=worker, name='worker2', daemon=True)
t2.start()
logging.info('stopping')
# 输出
2017-03-20 23:28:06,404 INFO [MainThread] starting
2017-03-20 23:28:06,436 INFO [worker1] starting
2017-03-20 23:28:07,492 INFO [worker2] starting
2017-03-20 23:28:07,492 INFO [MainThread] stopping # 主线程执⾏完成
2017-03-20 23:28:08,439 INFO [worker1] stopping # 主线程执⾏完成之后会等Non-Daemon线程执⾏完成,但是并不会等Daemon线程执⾏完成,即Daemon线程会随着主线程执⾏完成⽽释放
Thread.join()
如果想等Daemon线程执⾏完成之后主线程再退出,可以使⽤线程对象的 join() ⽅法
import logging
import time
import threading
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s] %(message)s')
def worker():
logging.info('starting')
time.sleep(2)
logging.info('stopping')
if __name__ == '__main__':
logging.info('starting')
t1 = threading.Thread(target=worker, name='worker1', daemon=False)
t1.start()
time.sleep(1)
t2 = threading.Thread(target=worker, name='worker2', daemon=True)
t2.start()
logging.info('stopping')
t1.join()
t2.join()
# 输出
2017-03-20 23:41:07,217 INFO [MainThread] starting
2017-03-20 23:41:07,243 INFO [worker1] starting
2017-03-20 23:41:08,245 INFO [worker2] starting
2017-03-20 23:41:08,246 INFO [MainThread] stopping
2017-03-20 23:41:09,243 INFO [worker1] stopping
2017-03-20 23:41:10,248 INFO [worker2] stopping
使⽤join函数只有主线程就需要等待Daemon线程执⾏完成在推出。
join函数的原型: join(self, timeout=None)
join⽅法会阻塞直到线程退出或者超时, timeout 是可选的,如果不设置timeout, 会⼀直等待线程退出。如果设置了timeout,会在超时之后退出或者线程执⾏完成退出。
因为join函数总是返回None,因此在超时时间到达之后如果要知道线程是否还是存活的,可以调⽤is_alive()⽅法判断线程是否存活。
threading常⽤⽅法
enumerate()
列出当前所有的 存活 的线程
>>> umerate()
[<_mainthread started>, , ]
timeout on t2 timerlocal()
import logging
import threading
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s [%(threadName)s] %(message)s')
ctx = threading.local()
ctx.data = 5
data = 'a'
def worker():
logging.info(data)
logging.info(ctx.data)
worker()
threading.Thread(target=worker).start()
# 输出
2017-03-21 00:02:08,102 INFO [MainThread] a
2017-03-21 00:02:08,113 INFO [MainThread] 5
2017-03-21 00:02:08,119 INFO [Thread-34] a
Exception in thread Thread-34:
Traceback (most recent call last):
File "/home/clg/.pyenv/versions/3.5.2/lib/python3.5/threading.py", line 914, in _bootstrap_inner
self.run()
File "/home/clg/.pyenv/versions/3.5.2/lib/python3.5/threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "", line 7, in worker
logging.info(ctx.data)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论