40.python全栈之路:进程与线程,,进程与线程1.什么是


进程与线程

1.什么是进程,什么是线程?

    进程,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竟争计算机系统资源的基本单位。每一个进程都有一个自己的地址空间,即进程空间或(虚空间)。进程空间的大小 只与处理机的位数有关,一个 16 位长处理机的进程空间大小为 216 ,而32 位处理机的进程空间大小为 232 。进程至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。

    线程,在网络或多用户环境下,一个服务器通常需要接收大量且不确定数量用户的并发请求,为每一个请求都创建一个进程显然是行不通的,——无论是从系统资源开销方面或是响应用户请求的效率方面来看。因此,操作系统中线程的概念便被引进了。线程,是进程的一部分,一个没有线程的进程可以被看作是单线程的。线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位。

2.进程与线程的区别?

    进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对

  其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一

  个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但

  对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

3.全局解释器锁(GIL)

    在进程上加一把锁,为了锁住多个线程,只要多个线程中的其中一个去访问了CPU,那么久锁住进程的资源,不允许其他线程访问同一资源

4.使用多线程及其其常用方法

  setDaemon(True):主线程不等待子线程

  join(n):主线程最多等待子线程n秒

import threadingimport timedef f1(a1, a2):    time.sleep(5)    print(‘666‘)t1 = threading.Thread(target=f1, args=(123, 111))t1.start()t2 = threading.Thread(target=f1, args=(123, 111))t2.start()t3 = threading.Thread(target=f1, args=(123, 111))t3.start()‘‘‘程序等待5秒后,3个线程同时输出666实现并发‘‘‘

5.线程锁

import threadingimport timeglobals_num = 0lock = threading.RLock()  # 实例化一个锁def Func():    lock.acquire()  # 获得锁,锁定当前访问资源    global globals_num    globals_num += 1    time.sleep(1)    print(globals_num)    lock.release()  # 释放锁,释放当前访问的资源for i in range(10):    t = threading.Thread(target=Func)    t.start()‘‘‘休息一秒 输出一个,因为资源被锁定,只能等资源被释放了才能使用全部变量不能像上一个例子一样并发‘‘‘

6.主线程控制子线程的方法(线程间通讯) 

    Event线程间通信最间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。

  用于主线程控制其他线程的执行。 Events 管理一个flag,这个flag可以使用set()设置成True或者

  使用clear()重置为False,wait()则用于阻塞,在flag为True之前。flag默认为False。

    Event.wait([timeout]) : 堵塞线程,直到Event对象内部标识位被设为true或超时(如果提供了参数timeout)。

    Event.set() :将标识位设为ture

    Event.clear() : 将标识伴设为false

    Event.isSet() :判断标识位是否为ture

import threadingdef do(event):  # 循环生成了10个线程    print(‘start‘)    event.wait()   # 线程产生阻塞,默认为flase,等待标志位为true,线程才继续执行    print(‘execute‘)event_obj = threading.Event()for i in range(10):    t = threading.Thread(target=do, args=(event_obj,))    t.start()event_obj.clear()   #falge设置为falseinp = input(‘input:‘)if inp == ‘true‘:    event_obj.set()  # flage设置为true

7.创建进程并使用 

#创建进程import multiprocessingimport time# 主进程的主线程创建了两个子进程,再由子进程的线程去执行f1方法def f1(a1):    time.sleep(2)    print(a1)if __name__ == ‘__main__‘:    t1 = multiprocessing.Process(target=f1, args=(11,))    # t1.daemon = True    t1.start()  # 运行进程 在Windows下需要写在__name__ == ‘__main__‘下    # t1.join()    t2 = multiprocessing.Process(target=f1, args=(11,))    # t2.daemon = True    t2.start()    print(‘end‘) 

8.进程与线程在资源共享问题上的区别

  进程:

# 进程不能共享数据,拷贝原数据并单独使用import multiprocessingli = []def foo(i):    li.append(i)    print(‘say hi‘,li)if __name__ == ‘__main__‘:    for i in range(10):        p = multiprocessing.Process(target=foo, args=(i,))        p.start()‘‘‘say hi [1]say hi [2]say hi [0]say hi [3]say hi [4]say hi [5]say hi [6]say hi [7]say hi [8]say hi [9]‘‘‘

  线程:

#线程与线程之间的内存是共享的import threadingli = []def foo(i):    li.append(i)    print(‘say hi‘,li)if __name__ == ‘__main__‘:    for i in range(10):        p = threading.Thread(target=foo, args=(i,))        p.start()‘‘‘say hi [0]say hi [0, 1]say hi [0, 1, 2]say hi [0, 1, 2, 3]say hi [0, 1, 2, 3, 4]say hi [0, 1, 2, 3, 4, 5]say hi [0, 1, 2, 3, 4, 5, 6]say hi [0, 1, 2, 3, 4, 5, 6, 7]say hi [0, 1, 2, 3, 4, 5, 6, 7, 8]say hi [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]‘‘‘  

9.进程间内存共享方法(默认不共享)

# manage.dict()共享数据  特殊的字典,支持进程之间共享数据from multiprocessing import Process, Managerdef Foo(i, dic):    dic[i] = 100 + i    for k, v in dic.items():        print(k, v)if __name__ == ‘__main__‘:    manage = Manager()    dic = manage.dict()    # dic = {}    for i in range(2):        p = Process(target=Foo, args=(i, dic))        p.start()        p.join()  # 避免主进程关闭后,子进程无法连接主进程,无法拿到数据    print(dic)‘‘‘用manage.dict,数据共享0 100  第一次只有1个数据0 100  第二次有两个数据哟1 101{0: 100, 1: 101}‘‘‘‘‘‘用普通字典,数据不共享0 1001 101{}‘‘‘

10.进程池与线程池

  进程池:python内部提供

# python提供了进程池from multiprocessing import Poolimport timedef Foo(i):    time.sleep(2)    print(i)if __name__ == ‘__main__‘:    pool = Pool(5)  # 最大能装5个进程,用一个加一个,不事先全部创完    # 申请进程,执行完后放回进程池    # pool.apply(Foo,(1,))    # pool.apply_async(func=Foo, args=(i,)).get()   执行完后,告诉我们一下,再放回进程池    # 执行完Foo方法后,将Foo方法的返回值,赋值给Bar方法的参数    # Bar方法,我们称之为回调函数    for i in range(40):        # pool.apply(Foo,(i,))  apply申请的时候,一个一个申请并执行        pool.apply_async(func=Foo, args=(i,))  # 并发进行,还能设置回调函数        print(‘666666666666‘)    pool.close()    pool.join()

  low版线程池:缺点在于,线程执行任务后,不能被重复使用,会等待python销毁它

import queueimport threadingimport timeclass ThreadPool(object):    def __init__(self, max_num=20):        self.queue = queue.Queue(max_num)  # 创建一个最大长度为20的队列        for i in range(max_num):            self.queue.put(threading.Thread)  # 传递类名,有20个类名的队列,都指向同一个类    def get_thread(self):        return self.queue.get()  # 当队列为空的时候,get则等待    def add_thread(self):        self.queue.put(threading.Thread)def func(pool, a1):    time.sleep(1)    print(a1)    pool.add_thread()p = ThreadPool(10)for i in range(100):    thread = p.get_thread()  # ret 等价于 threading.Thread,是个类名    t = thread(target=func, args=(p, i))  # 创建一个线程,将线程池对象传入func中,在func结束的时候,再将该线程重新放入线程池    t.start()  # 启动线程    # 在队列中放类,线程放在内存在 等待销毁,这样是不合理的,我们可以优化,线程继续做第二件事情    # 在队列里面放任务,让线程不停的取任务,重复利用线程

  

40.python全栈之路:进程与线程

评论关闭