python 35 多线程

多线程

1. 线程

​ 开启一个进程,操作系统会开辟一个进程空间,将进程的数据资源全部复制一份,然后cpu使线程执行代码。

进程负责开辟空间、加载数据资源,线程负责执行。

2. 线程vs进程

	1. 开启进程的开销大;
  1. 开启进程的速度满,线程比进程快10—100倍;
    3. 同一进程的线程之间可共享数据,进程与进程之间使隔离的。

线程的应用:多线程并发。比多进程并发开销小、速度快,可共享数据。

3. 开启线程的两种方法。

# 第一种方式
from threading import Thread

def task():
    print("===子线程")

if __name__ == '__main__':		# 在windows下也可不写
    t1 = Thread(target=task)
    t1.start()
    print('===主线程')	
"""
===子线程
===主线程
"""
# 第二种方式
from threading import Thread

class MyThread(Thread):
    
    def __init__(self, name)
    super().__init()
    self.name=name

    def run(self):
        print("==={self.name}子线程")

if __name__ == '__main__':
    t1 = MyThread("meet")
    t1.start()
    print('===主线程')
"""
===meet子线程
===主线程
"""

4. 线程的特性

  1. 同一进程中,每个线程的pid相同,因为它们在同一进程内。
  2. 主线程需等待其他子线程结束后,才能结束。(因为主线程结束代表本进程结束,而子线程需依赖进程存活。)
  3. 同一进程内的数据资源对于本进程的多个进程来说是共享的。

5. 线程的相关方法

Thread实例对象方法:
	t.is_alive()(t.isAlive())	#判断线程是否活着
    t.getName()			# 获取线程名
    print(t.name)		# 获取线程名
    t.setName()			# 设置线程名

threading模块方法:
	currentThread()		# 获取当前线程的对象
    enumerate()			# 获取进程中所有线程对象,返回列表
    activeCount()		# 获取活跃的线程数量
from threading import Thread,currentThread,enumerate,activeCount
import time

def task():
    time.sleep(1)
    print("is task")

if __name__ == '__main__':
    t1 = Thread(target=task,name='===子线程')
    t1.start()
    print(t1.name)  # ===子线程
    print(t1.is_alive())    # True
    t1.setName('子线程')
    print(t1.getName())     # 子线程

    print(currentThread())    #主线程对象
    print(enumerate())      # 列表中两个线程对象 
    print(activeCount())    # 2
    print('===主线程')
"""
True
子线程
<_MainThread(MainThread, started 14876)>
[<_MainThread(MainThread, started 14876)>, <Thread(子线程, started 8736)>]
2
===主线程
is task
"""

6. join 阻塞

​ 告知主线程需等待子线程执行结束后,再开始执行。

from threading import Thread
import time
def sayhi(name):
    time.sleep(2)
    print('%s say hello' %name)

if __name__ == '__main__':
    t=Thread(target=sayhi,args=('meet',))
    t.start()
    t.join()
    print(t.is_alive())
    print('主线程')
'''
meet say hello
False
主线程
'''

7. 守护线程 daemon

若主线程运行结束,守护线程也会跟着结束。

对主线程来说,运行完毕指的是本进程内所有非守护线程统统运行完毕,主线程才算运行完毕(若守护线程的生命周期小于其他的线程,会先结束)。

from threading import Thread
import time

def foo():
    print(123)  
    time.sleep(3)
    print("end123")  

def bar():
    print(456)  
    time.sleep(1)
    print("end456")

if __name__ == '__main__':
    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True		# 设置t1为守护进程
    t1.start()
    t2.start()
    print("main---") 
"""
123
456
main---
end456
"""
# 面试题---迷惑人的例子
from threading import Thread
import time

def foo():
    print(123)  # 1
    time.sleep(1)
    print("end123")  # 4

def bar():
    print(456)  # 2
    time.sleep(2)
    print("end456")  # 5

if __name__ == '__main__':

    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True		# 设置t1为守护进程
    t1.start()
    t2.start()
    print("main-------")  # 3
    
"""
123
456
main---
end123		
end456
"""
# 因为bar需2s执行完毕,2s足够守护进程的foo执行完毕。因此在主线程结束前,守护线程以及结束。

8. 互斥锁

​ 多线程的同步锁与多进程的同步锁是一个道理,就是多个线程抢占同一个数据(资源)时,我们要保证数据的安全,合理的顺序,因此需串行。

from threading import Thread
from threading import Lock
import time
import random

x = 100

def task(lock):
    global x
    lock.acquire()
    num = x
    time.sleep(random.random())
    x = num-1
    lock.release()

if __name__ == '__main__':
    mutex = Lock()
    for i in range(100):
        t = Thread(target=task, args=(mutex,))
        t.start()
    time.sleep(2)
    print(f'主线程{x}')		# 输出不固定 串行执行

posted @ 2019-08-23 17:23  SensorError  阅读(171)  评论(0编辑  收藏  举报