多线程(1) 1. 线程内容 2. 线程开启的两种方式 3. 进程vs线程创建速度 4. 子线程共享资源 5. 线程的join方法 6. 了解进程的join 7. 线程其他相关用法 8. 守护线程

多线程(1)
1. 线程内容
2. 线程开启的两种方式
3. 进程vs线程创建速度
4. 子线程共享资源
5. 线程的join方法
6. 了解进程的join
7. 线程其他相关用法
8. 守护线程

'''
初识别线程
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程,cpu真正的执行单位是线程
在工厂中,每个车间都有房子,而且每个车间默认就有一条流水线

操作系统 ===》工厂
进程 ===》车间
线程 ===》流水线
cpu ===》电源

线程:cpu最小的执行单位
进程:资源集合/资源单位
线程运行 = 运行代码
进程运行 = 各种资源 + 线程

右键运行:
申请内存空间,先把解释器丢进去并且把代码丢进去,运行代码(线程)

进程和线程的区别:

过程描述的区别
线程 ==》单指代码的执行过程
进程 ==》资源的申请与销毁的过程

进程内存空间彼此隔离
同一个进程下的线程共享资源

进程和线程的创建速度
进程需要申请资源开辟空间  慢
只是告诉操作系统一个执行方案
'''

2. 线程开启的两种方式

# 方式一
from threading import Thread
import time

def task():
    print('线程 start')
    time.sleep(2)
    print('线程 end')

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()   # 告诉操作系统开一个线程 开启线程无需申请内存空间会非常快
    print('主')


# 1 同一个进程下没有父子线程之分大家地位都一样。
# 2 右键运行发生了什么事情?开启了一个进程,开辟了一个内存空间,把代码都丢进去,然后运行代码(自带的主线程运行),然后又开启了一个子线程。

# 主线程结束和子线程结束没有任何必然联系,比如主线程运行结束,子线程还在运行当中。不是主线程在等待子线程结束,是进程在等待自己的所有线程结束。


# 方式二
from threading import Thread
import time
# 进程等待所有线程结束才会结束

class Myt(Thread):
    def run(self):
        print('子线程 start')
        time.sleep(2)
        print('子线程 end')

# if __name__ == '__main__':
t = Myt()
t.start()
print('主线程')

3. 进程vs线程创建速度

from threading import Thread
from multiprocessing import Process
import time

def task(name):
    print(f'{name} is running')
    time.sleep(3)
    print(f'{name} is end')

if __name__ == '__main__':
    t = Thread(target=task,args=('子线程',))
    p = Process(target=task,args=('子进程',))
    t.start()
    p.start()
    print('主')


'''
开启子线程的打印效果:
子线程 is running
主
子线程 is end

开启子进程的打印效果:
主
子进程 is running
子进程 is end

进程和线程的创建速度
开启子进程需要申请资源开辟空间  慢
开启子线程只是告诉操作系统一个执行方案  快
'''

4. 子线程共享资源

from threading import Thread
import time,os

x = 100
def task():
    global x
    x = 50
    print(os.getpid())  # 1816

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    time.sleep(2)
    print(x)  # 50
    print(os.getpid())  # 1816

# 首先子线程修改了全局变量为50,主线程等待子线程修改完毕后打印x为50
# 说明同一个进程下所有的线程共享同一份内存空间
# 主进程下的每个线程都跟主进程的pid一样

5. 线程的join方法

from threading import Thread
import time

def task():
    print('子线程 start')
    time.sleep(2)
    print('子线程 end')

t = Thread(target=task)
t.start()
t.join()  # 主线程等待子线程运行结束
print('主线程')

# 进程的join是当前线程在等子进程运行结束并不影响其他线程


from threading import Thread
import time

def task(name,n):
    print(f'{name} start')
    time.sleep(n)
    print(f'{name} end')

t1 = Thread(target=task,args=('线程1',1))
t2 = Thread(target=task,args=('线程2',2))
t3 = Thread(target=task,args=('线程3',3))
start = time.time()
t1.start()
t2.start()
t3.start()
t1.join()  # 1s
t2.join()  # 1s
t3.join()  # 1s
end = time.time()
print(end - start)   # 3.002460479736328

# 在单核的情况下,多个线程是如何利用cpu的???

6. 了解进程的join

from multiprocessing import Process
from threading import Thread
import time

def task1():
    print('进程 start')
    time.sleep(5)
    print('进程 end')

def task2():
    print('子线程 start')
    time.sleep(2)
    print('子线程 end')

if __name__ == '__main__':
    p = Process(target=task1)
    t = Thread(target=task2)
    t.start()   # 开线程
    p.start()   # 开进程
    print('子进程join开始')
    p.join()  # 主进程的主线程等待子进程运行结束  当前线程等待当前进程下的子进程结束,然后往下运行
    print('主')

7. 线程其他相关用法

from threading import Thread,currentThread,enumerate,activeCount
import time

def task():
    print('子线程 start')
    time.sleep(2)
    print('子线程 end')
    print(enumerate())     # 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    # print(currentThread(),'子线程')  # 返回当前的线程变量

if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t1.start()
    t2.start()

    print(t1.is_alive())   # True  # 返回线程是否活动的
    print(t1.getName())    # Thread-1  # 返回线程名
    print(t2.getName())    # Thread-2  # 返回线程名
    t1.setName('班长')     # 设置线程名
    print(t1.getName())    # 班长
    print(currentThread().name)   # MainThread
    print(enumerate())   # [<_MainThread(MainThread, started 14420)>, <Thread(班长, started 3260)>, <Thread(Thread-2, started 10844)>]
    print(activeCount())   # 3    # 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
    print(len(enumerate()))  # 3

8. 守护线程

# 守护线程 守护的是进程的运行周期
'''
守护线程首先是一个线程
    守护线程守护到当前进程运行结束
    有未完成的子进程阶段会守护
    有未完成的其他子线程也均会守护

守护进程首先是一个进程
    守护进程守护到当前进程的最后一行代码结束
'''
from threading import Thread,enumerate,currentThread
import time

def task1():
    print('守护线程 start')
    print(currentThread())
    time.sleep(10)
    print('守护线程 end')

def task2():
    print('子线程 start')
    time.sleep(5)
    print(enumerate())
    print('子线程 end')

if __name__ == '__main__':
    t1 = Thread(target=task1)
    t2 = Thread(target=task2)
    t1.daemon = True
    t2.start()
    t1.start()
    print('主')

# 当主线程已经结束的时候,其他子线程没有结束的时候打印当前的活跃的线程发现有守护线程