object 请求 ase lock 任务 是个 num range
进程,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竟争计算机系统资源的基本单位。每一个进程都有一个自己的地址空间,即进程空间或(虚空间)。进程空间的大小 只与处理机的位数有关,一个 16 位长处理机的进程空间大小为 216 ,而 32 位处理机的进程空间大小为 232 。进程至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。
线程,在网络或多用户环境下,一个服务器通常需要接收大量且不确定数量用户的并发请求,为每一个请求都创建一个进程显然是行不通的,——无论是从系统资源开销方面或是响应用户请求的效率方面来看。因此,操作系统中线程的概念便被引进了。线程,是进程的一部分,一个没有线程的进程可以被看作是单线程的。线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对
其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一
个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但
对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
在进程上加一把锁,为了锁住多个线程,只要多个线程中的其中一个去访问了 CPU,那么久锁住进程的资源,不允许其他线程访问同一资源
setDaemon(True):主线程不等待子线程
join(n):主线程最多等待子线程 n 秒
- import threading
- import time
- def 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
- 实现并发
- '''
- import threading
- import time
- globals_num = 0
- lock = 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()
- '''
- 休息一秒 输出一个,因为资源被锁定,
- 只能等资源被释放了才能使用全部变量
- 不能像上一个例子一样并发
- '''
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 threading
- def 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设置为false
- inp = input('input:')
- if inp == 'true':
- event_obj.set() # flage设置为true
- #创建进程
- import multiprocessing
- import 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')
进程:
- # 进程不能共享数据,拷贝原数据并单独使用
- import multiprocessing
- li = []
- 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 threading
- li = []
- 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]
- '''
- # manage.dict()共享数据 特殊的字典,支持进程之间共享数据
- from multiprocessing import Process, Manager
- def 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 100
- 1 101
- {}
- '''
进程池:python 内部提供
- # python提供了进程池
- from multiprocessing import Pool
- import time
- def 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 queue
- import threading
- import time
- class 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 全栈之路:进程与线程
来源: http://www.bubuko.com/infodetail-2157124.html