python中线程的接口与进程基本上一样,只有少数不同,下面看看线程的方法:
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。
threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
开启线程的两种方式:
#方式一
import time
from threading import Thread
def sayhi(name):
time.sleep(2)
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('andy',))
t.start()
print('主线程')
#方式二
class Sayhi(Thread):
# 当我们为线程添加属性时一定要重写父类的__init__方法,调用super().__init__()
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
time.sleep(2)
print('%s say hello' % self.name)
if __name__ == '__main__':
t = Sayhi('andy')
t.start()
print('主线程')
同一进程内的线程共享数据
def work():
global n
n = 0
if __name__ == '__main__':
n = 1
t = Thread(target=work)
t.start()
t.join()
print('主', n)
# 查看结果为0,因为同一进程内的线程之间共享进程内的数据
#在进程内:
if __name__ == '__main__':
n=100
p=Process(target=work)
p.start()
p.join()
print('主',n)
#毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100
另外,在同一进程下,线程的getpid()得到的id与进程id一样,都是开启该线程的进程id.
但线程中的主守护线程与进程的守护进程是有很大区别的;下面看实例
import time
from threading import Thread
def foo():
print('foo')
time.sleep(1)
print("end foo")
def bar():
print('bar')
time.sleep(3)
print("end bar")
t1 = Thread(target=foo)
t2 = Thread(target=bar)
t1.daemon = True
t1.start()
t2.start()
print("main-------")
#输出
foo
bar
main-------
end foo
end bar
我们分析一下为什么是这样的:
首先,t1启动,打印foo,然后睡1秒,接着t2启动,打印bar, 然后睡3秒,然后运行主线程 打印main, 但主线程要等待其它所有 非守护线程 结束后才能结束,所以它要等待bar执行完,也就是要等3秒,在此过程中foo睡完一秒,然后打印 end foo, 此时守护线程代码执行完毕,但它的主子还在,所以它也继续等待。 主线程等待bar睡3秒后结束才结束,然后守护线程才结束。
假若,我把foo的sleep时间改成3秒,而barsleep时间改成1秒,情况则是:end foo不会打印:下面看分析过程:
t1启动,打印foo, 然后sleep 3秒, 接着t2启动, 打印bar, 然后执行main , 此时还有t2这个非守护线程在执行,所以主线程不能结束,仍在等待。一秒后,打印end bar, 除t1这个守护线程外的非守护线程都结束了,所以主线程也就结束了,此时守护线程t1仍在sleep, 但主线程已经结束,它也只得陪葬,就没来得及执行end foo.
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁 ,但运行完毕并非是指终止运行。