Python 线程

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运行完毕后被销毁 ,但运行完毕并非是指终止运行。

上一篇:Python 互斥锁

下一篇:Python 线程锁