线程

线程和进程概念

进程:数据隔离,资源分配的最小单位,可以利用多核,操作系统调度,开启关闭切换时间消耗大
multiprocessing 如何开启进程 start join
进程有数据不安全问题Lock
进程之间可以通信ipc
队列(安全) 管道(不安全)
第三方工具
进程之间可以通过Manager类实现数据共享
一般情况下开启的进程数不会超过cpu个数的两倍



线程
能被操作系统调度(给CPU执行)的最小单位
同一个进程中的多个线程能同时被cpu执行
数据共享,操作系统调度的最小单位可以利用多核,操作系统调度,
  数据不安全,开启关闭切换时间消耗小

在CPython中的多线程 - 节省io操作的时间
gc 垃圾回收机制
引用计数 分代回收
全局解释器锁的出现主要是为了完成gc的回收机制,
   对不同线程的引用计数的变化记录的更加准确
全局解释器锁 GIL(global interpreter lock)
导致了同一个进程中的多个线程只能有一个线程能真正被cpu执行
节省的是io操作的时间,而不是cpu计算的时间,因为cup的计算熟读非常快,
  在大部分情况下,我们没有办法把一条进程中所有的io操作都规避掉
from threading import Thread, current_thread, enumerate, active_count
import time


def func(i):
    print(f"开始{i}", current_thread().ident)    # 函数内拿线程id current_thread().ident
    time.sleep(1)
    print(f"结束{i}")

for i in range(10):
    t1 = []
    t = Thread(target=func, args=(i, ))
    t.start()
    print(t.ident)
    t1.append(t)
print(enumerate(), active_count())
for t in t1:
    t.join()
    print("所有线程都执行完了")



# 函数内拿线程id current_thread().ident
# 线程不能从外部关闭
# 所有的子线程只能是自己执行完所有代码之后就关闭
# enumerate 列表  存储了所有活着的线程对象,包括主线程
# activ_count  储存了所有活着的线程个数



# 面向对象的方式启动线程
from threading import Thread
class MyThread(Thread):
    def __init__(self,a,b):
        self.a = a
        self.b = b
        super().__init__()
    def run(self):
        print(self.ident)
t = MyThread(1,2)
t.start()
t.run()


线程共享数据
"""
线程之间的数据共享
"""

from threading import Thread
n = 100

def func():
    global n
    n -= 1
t1 = []
for i in range (100):
    t = Thread(target=func)
    t.start()
    t1.append(t)
for t in t1:
    t.join()
print(n)

 

线程数据不安全
from threading import Thread
n = 0
def add():
    for i in range(500000):
        global n
        n += 1
def sub():
    for i in range(500000):
        global n
        n -= 1

tlist = []
for i in range(2):
    t1 = Thread(target=add)
    t1.start()
    t2 = Thread(target=sub)
    t2.start()
    tlist.append(t1)
    tlist.append(t2)
for t in tlist:
    t.join()
print(n)

 

线程锁
from threading import Thread, Lock
n = 0
def add(lock):
    with lock:
        for i in range(500000):
            global n
            n += 1
def sub(lock):
    with lock:
        for i in range(500000):
            global n
            n -= 1

tlist = []
lock = Lock()
for i in range(2):
    t1 = Thread(target=add,args=(lock, ))
    t1.start()
    t2 = Thread(target=sub, args=(lock, ))
    t2.start()
    tlist.append(t1)
    tlist.append(t2)
for t in tlist:
    t.join()
print(n)

 

守护线程
import time
from threading import Thread

def son():
    while True:
        print("in son")
        time.sleep(1)

t = Thread(target=son)
t.daemon = True
t.start()
"""
主线程会先等子线程结束后结束
    主线程结束进程就会结束
守护线程随着主线程的结束而结束
守护线程会在主线程的代码结束之后继续守护其他子线程

守护进程  会随着主进程的代码结束而结束
    如果主进程代码结束之后还有其他子进程在运行,守护进程不守护
守护线程  随着主线程的结束而结束
    如果主线程代码结束之后还有其他子线程在运行,守护线程也守护
    
守护进程和守护线程的结束原理不一样
守护进程需要主进程来回收资源
守护线程是随着进程的结束才结束的
    其他子线程——》主线程结束——》主进程结束——》整个进程中的所有资源都被回收——》守护线程也会被回收
    
进程是资源分配单位
子进程都需要它的父进程来回收资源
线程都是进程中的资源
所有的线程都会随着进程的结束而被回收

"""

 




posted @ 2023-02-22 20:20  Wchime  阅读(30)  评论(0)    收藏  举报