线程基础

落花浮王杯 提交于 2020-03-10 12:17:54

线程基础

一、线程和进程的区别

  • 进程:
    • 进程之间数据隔离,每一个进程分配一块内存
    • 进程可以使用多核处理,操作系统调度
    • 进程是资源计算机资源份分配的最小单位
    • 进程有数据不安全的问题,需要用到锁和信号量
    • 进程之间本身无法通信,但是可以使用第三方模块和工具来实现通信IPC
      • 队列:基于socket、pickle和lock来实现,队列的数据因为锁机制是安全的
      • 管道:基于socket和pickle来实现,数据是不安全的
      • 第三方工具:已开发完成,可以直接使用,稳定安全,工作中基本上都是使用第三方工具
    • 进程之间可以通过Manager模块实现数据的共享,也被称为内存共享
    • 进程开启的、关闭和切换对资源的消耗很大
    • 一般情况下进程开启最多不要超过CPU核数的两倍,最佳的数量是CPU核数+1,CPU核数:os.cpu_count()获取
  • 线程:
    • 线程在进程之内
    • 能被操作系统调度给CPU执行的最小单位
    • 线程之间数据本身是可以共享的,但是也因此数据变得不安全
    • 同一个进程中的多个线程是可以被CPU同时执行的,可以利用多核
    • 线程开启、关闭和切换对资源的消耗很小,速度很快

二、CPython的垃圾回收机制

在CPython程序中gc来负责处理垃圾的回收工作,当一个线程执行的时候,gc会对该线程进行监控,但是当一个进程中多个线程同时工作的时候,gc机制无法很好的对每一个线程进行监控,为了能够监控每一个线程,在CPython中引入了锁机制,虽然是多线程,但是CPU在调度的时候通过锁机制来控制数量,每次只能有一个线程可以获得钥匙,其他线程等待该线程执行完后,才能获取钥匙继续执行,这样gc可以监控到每一个线程,虽然是多核,但是执行的结果却是单核并发,不是多核并行。这里的锁被成为全局解释器锁(GIL:global
interpreter Lock)

线程的开启

  • 线程的开启方式和进程完全一样,只不过引用的模块不同,两种方式:直接实例化和继承方式
  • 模块导入:from threading import Thread
from threading import Thread
import time
import random

def func(i):
    print('start%s' % i)
    time.sleep(random.random())
    # 阻塞
    print('end%s' % i)


if __name__ == '__main__':
    t_list = []
    for i in range(10):
        t = Thread(target=func, args=(i,))
        t.start()
        t_list.append(t)
    [t.join() for t in t_list]
    # 阻塞,异步变为同步
    print('执行结束')
  • 线程不能从外部关闭,只能是自己执行完代码之后再关闭,所以没有terminate方法
  • 线程号:t.ident来获取,每一个线程的线程号不一样,但是一个进程中的所有线程获取到的进程号是一样的。
  • 进程中可以在子进程里获取每一个子进程的pid,同样的子线程也可以通过current_thread()获取子线程的对象,通过对象获取线程号,每一个进程中都有唯一的一个主线程,无论是否开启子线程,主线程都存在。 from threading import current_thread
  • 获取所有的线程对象:enumerate(),列表类型,线程对象中除了开启的子线程,必须加上一个主线程,即开启10个子线程,获取的是11个线程
for i in range(10):
  t = Thread(target=func)
  t.start()
print(enumerate())

'''结果是:
[<_MainThread(MainThread, started 139753402050368)>, <Thread(Thread-1, started 139753362441984)>, <Thread(Thread-2, started 139753354049280)>, <Thread(Thread-3, started 139753345656576)>, <Thread(Thread-4, started 139753135535872)>, <Thread(Thread-5, started 139753127143168)>, <Thread(Thread-6, started 139753118750464)>, <Thread(Thread-7, started 139753110357760)>, <Thread(Thread-8, started 139753101965056)>, <Thread(Thread-9, started 139753093572352)>, <Thread(Thread-10, started 139753085179648)>]

'''
  • 获取开启线程的总数:active_count(),开启线程数+主线程
  • 线程之间可以直接进行数据的共享
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!