进程和线程

线程参考文档

线程是操作系统能够进行运算调度的最小单位,它被包含在进程中,是进程中的实际运作单位

一个进程实际上可以由多个线程的执行单元组成。每个线程都运行在进程的上下文中,并共享同样的代码和全局数据。

由于在实际的网络服务器中对并行的需求,线程成为越来越重要的编程模型,因为多线程之间比多进程之间更容易共享数据,同时线程一般比进程更高效


  • 线程是操作系统能够进行运算调度的最小单位。它被包含在进程中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中科并发多个线程,每条线程并行执行不同的任务。
  • OS调度CPU的最小单位|线程:一堆指令(控制流),线程是负责执行的指令集
  • all the threads in a process have the same view of the memory在同一个进程里的线程是共享同一块内存空间的

  • IO操作不占用CPU(数据读取存储),计算操作占用CPU(1+1...)
  • python多线程,不适合CPU密集型操作,适合IO密集型操作

进程

程序并不能单独和运行只有将程序装载到内存中,系统为他分配资源才能运行,而这种执行的程序就称之为进程。

程序和进程的区别在于:程序是指令的集合,它是进程的静态描述文本;进程是程序的一次执行活动,属于动态概念。


进程是操作系统对一个正在运行的程序的一种抽象。即进程是处理器,主存,IO设备的抽象

操作系统可以同时运行多个进程,而每个进程都好像在独占的使用硬件


  • 每个程序在内存里都分配有独立的空间,默认进程间是不能互相访问数据和操作的
  • (QQ,excel等)程序要以一个整体的形式暴露给操作系统管理,里面包含各种资源的调用(调用内存的管理、网络接口的调用等),对各种资源管理的集合就可以称为进程。
  • 例如整个QQ就可以称为一个进程
  • 进程要操作CPU(即发送指令),必须先创建一个线程;
  • 进程本身不能执行,只是资源的集合,想要执行必须先生成操作系统进行调度运算的最小单元-》线程;一个进程要执行,必须至少拥有一个线程。当创建一个进程时,会自动创建一个线程

进程和线程的区别?

  • 线程共享创建它的进程的地址空间,进程的内存空间是独立的
  • 多个线程直接访问数据进程的数据,数据时共享的;一个父进程中的多个子进程对数据的访问其实是克隆,相互之间是独立的。
  • 线程可以直接与创建它的进程的其他线程通信;一个父进程的子进程间的通信必须通过一个中间代理来实现
  • 新的线程容易创建;创建新进程需要对其父进程进行一次克隆
  • 线程可以对创建它的进程中的线程进行控制和操作,线程之间没有实际的隶属关系;进程只能对其子进程进行控制和操作
  • 对主线程的更改(取消、优先级更改等)可能影响进程的其他线程的行为;对进程的更改不会影响子进程

多线程并发的例子

import threading,time

def run(n)
    print("task",n)
    time.sleep(2)

t1 = threading.Thread(target=run,args=("t1",))#target=此线程要执行的代码块(函数);args=参数(不定个数参数,只有一个参数也需要加`,`,这里是元组形式)
t2 = threading.Thread(target=run,args=("t2",))
t1.start()
t2.start()
  • 启动多个线程
import threading,time

def run(n)
print("task",n)
time.sleep(2)

start_time = time.time()
for i to range(50)
    t = threading.Thread(target=run,args=("t%s" %i ,))
    t.start()

print('const',time.time()-start_time)
  • 这里统计的执行时间比2秒小很多,因为主线程和由它启动的子线程是并行的

  • join()等待线程执行完毕再继续相当于wait

import threading
import time

def run(n):
    print('task:',n)
    time.sleep(2)

start_time = time.time()
thread_list = []
for i in range(50):
    t = threading.Thread(target=run,args=(i,))
    t.start()
    #如果这里加入t.join()则等待每个线程执行完毕再进行下一个线程,多线程变成了串行
    thread_list.append(t)

for t in thread_list:
    t.join()#在线程启动后(start),加入join,等待所有创建的线程执行完毕,再执行主线程

print('cont:',time.time()-start_time)
print(threading.current_thread(),threading.active_count())
#threading.current_thread()显示当前进程,threading.active_count()当前进程活跃个数
  • 这里结果为2秒多一点,统计时间正确,用于此场景时,join()必须在所有线程的start()之后,否则变为多线程串行,多线程就无意义了

守护线程

  • 不加jion()时,主线程和子线程是并行的,线程之间是并行关系;加了join(),加了join()的线程执行完毕才会继续其他线程
  • 设为【守护线程】,主线程不等待子线程执行完毕,直接执行;程序会等主线程执行完毕,但不会等待守护线程
import threading
import time

def run(n):
    print('task:',n)
    time.sleep(2)

start_time = time.time()
thread_list = []
for i in range(50):
    t = threading.Thread(target=run,args=(i,))
    t.t.setDaemon(True)#设置为守护线程,必须在start之前
    #守护=》仆人,守护主人(主进程/线程),主人down了,守护的仆人直接结束
    t.start()
    thread_list.append(t)
print('cont:',time.time()-start_time)
#主线程不是守护线程(也不可设置为守护线程),不等待子线程(设置为守护线程)等待2秒的时间,直接执行最后一句print()

线程锁

  • 每个线程在要修改公共数据时,为了避免自己在还没改完的时候别人也来修改此数据,可以给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。
  • 线程锁将线程变为串行
def run(n):
    lock.acquire()#创建锁
    global num
    num +=1
    lock.relsase#释放锁

lock = threading.Lock()#实例化锁
for i in range(50):
    t = threading.Thread(target=run,args=(i,))
    t.start()

print('num:',num)

RLock(递归锁)

  • 多层锁的时候使用,说白了就是在一个大锁中还要再包含子锁
import threading,time

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num +=1
    lock.release()
    return num
def run2():
    print("grab the second part data")
    lock.acquire()
    global  num2
    num2+=1
    lock.release()
    return num2
def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res,res2)


if __name__ == '__main__':

    num,num2 = 0,0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num,num2)

信号量(Semaphore)

  • 互斥锁(线程锁) 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
  • 每释放一个锁,立刻进一个线程(例如socket_server中的并发数限制)
import threading,time

def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s
" %n)
    semaphore.release()

if __name__ == '__main__':

    num= 0
    semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
    for i in range(20):
        t = threading.Thread(target=run,args=(i,))
        t.start()

while threading.active_count() != 1:
    pass #print threading.active_count()
else:
    print('----all threads done---')
    print(num)

继承式多线程

  • 一般不用

通过类的形式=》多线程

import threading,time

class MyThread(threading.Thread)
    def __inin__(self,n)
        super(MyThread,self).__init__(n)
        self.n = n
    
    def run(self)#这里方法名必须为run
        print("running task",self.n)
        time.sleep(2)

t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()
原文地址:https://www.cnblogs.com/limich/p/7477072.html