一、进程与线程的相关概念

1、什么是进程

进程是一个程序在一个数据集上的一次动态执行过程。

进程一般由程序,数据集,进程控制块三部分组成。

2、什么是线程

线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。

3、线程与进程的关系

线程不能独立存在,一个线程肯定有一个父进程。进程也不能独立存在,它一定也包含一个进程。可以理解为进程是线程的容器。进程可以包含多个线程,但是线程只能依托一个进程存在。

二、python的线程模块threading

threading模块是建立在thread模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading模块是对thread的二次封装。

注意:全局解释器锁GIL,决定了python的多线程只能用到一个cpu。

1、下面是两种threading的调用方式:

(1)、直接使用方式例子

 import threading

 def func(num):
print("Hi %s threading" % num) t1 = threading.Thread(target=func,args=(1,))
t2 = threading.Thread(target=func,args=(2,))
t1.start()
t2.start()

直接使用threading模块的方式

(2)、继承threading的方式

 import threading

 class Mythread(threading.Thread):
def __init__(self,num):
threading.Thread.__init__(self)
self.num = num def run(self):
print("Hi %s threading" % self.num) t1 = Mythread(1)
t2 = Mythread(2)
t1.start()
t2.start()

类的继承方式

2、threading模块的join(),setDaemon()方法

join():在子线程完成运行之前,这个子线程的父线程将被阻塞。

setDaemon(True):将线程声明为守护线程,必须在start()方法之前进行设置。当线程设置为守护线程的话,不管线程任务有没有执行完,主线程执行完毕后都会随着主线程一起退出。

例子:

 import threading,time

 def to_sing(name):
print("Come to sing %s" % name)
time.sleep(5) def to_dance(name):
print("Come to dance %s" % name)
time.sleep(3) if __name__=="__main__":
sing = threading.Thread(target=to_sing,args=("Tom",))
dance = threading.Thread(target=to_dance,args=("lisa",)) sing.start()
dance.start()
sing.join()
dance.join() #join方法放在这里的话起到的效果就是后面的print会等到sing方法和dance方法都执行完以后才会执行。如果不放在这里的话效果又是不一样的。
print("party is end...")

join()方法使用

 import threading,time

 def to_sing(name):
print("Come to sing %s" % name)
time.sleep(5) def to_dance(name):
print("Come to dance %s" % name)
time.sleep(30) if __name__=="__main__":
sing = threading.Thread(target=to_sing,args=("Tom",))
dance = threading.Thread(target=to_dance,args=("lisa",)) sing.start()
dance.setDaemon(True) #必须放在start前面,这个例子就会出现运行五秒后dance的线程就和主线程一起退出了,因为设置它被设置成了守护线程。
dance.start()
sing.join()
print("party is end...")

setDaemon()使用

其他的方法:

# run():  线程被cpu调度后自动执行线程对象的run方法
# start():启动线程活动。
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。 threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

3、同步锁,递归锁

(1)、不用同步锁的情况下,开启多线程

 import time
import threading def addNum():
global num temp = num
time.sleep(0.0001)
num = temp-1 num = 100
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for j in thread_list:
j.join() print("final num",num) #终端打印
final num 93

不用同步锁的情况出现的问题

这个例子说明:当多线程操作同一个对象的时候很容易出现取到相同值的问题

使用同步锁解决问题

 import time
import threading def addNum():
global num
r.acquire() #将运行过程锁住
temp = num
time.sleep(0.0001)
num = temp-1
r.release() #释放锁 num = 100
thread_list = [] r = threading.Lock() #拿到多线程的锁
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t) for j in thread_list:
j.join() print("final num",num) #打印
final num 0

用同步所来解决问题的例子

这个例子也可以说明一个问题,用同步锁的情况下就是我拿到了数据,在我执行完逻辑之前,其他线程等待。是一个串行操作了。

(2)、使用多把同步锁造成死锁的例子和使用递归锁解决死锁的问题

 import time
import threading class MyThread(threading.Thread):
def task_A(self):
lock_A.acquire()
print(self.name,"gotLockA",time.ctime())
time.sleep(2)
lock_B.acquire()
print(self.name,"gotLockB",time.ctime())
lock_B.release()
lock_A.release() def task_B(self):
lock_B.acquire()
print(self.name, "gotLockB", time.ctime())
time.sleep(2)
lock_A.acquire()
print(self.name, "gotLockA", time.ctime())
lock_A.release()
lock_B.release() def run(self):
self.task_A()
self.task_B() lock_A = threading.Lock()
lock_B = threading.Lock() t = []
for i in range(5):
t.append(MyThread())
for i in t :
i.start()
for j in t:
j.join() #例子执行的流程
#开起5个线程,当第一个线程执行A,同时用了a锁和b锁,这个时候其他线程都在等待,当A线程执行完task_A释放了a、b锁后,执行任务task_B,拿到了B锁。这时线程B拿到了a锁把任务锁住了,等待b锁释放,但是b锁已经被A线程拿到,所以造成了死锁。

多把同步锁造成死锁

使用递归锁来解决以上问题

 import time
import threading class MyThread(threading.Thread):
def task_A(self):
lock_R.acquire()
print(self.name,"gotLockA",time.ctime())
time.sleep(2)
lock_R.acquire()
print(self.name,"gotLockB",time.ctime())
lock_R.release()
lock_R.release() def task_B(self):
lock_R.acquire()
print(self.name, "gotLockB", time.ctime())
time.sleep(2)
lock_R.acquire()
print(self.name, "gotLockA", time.ctime())
lock_R.release()
lock_R.release() def run(self):
self.task_A()
self.task_B() # lock_A = threading.Lock()
# lock_B = threading.Lock()
lock_R = threading.RLock() #用递归锁代替同步锁 t = []
for i in range(5):
t.append(MyThread())
for i in t :
i.start()
for j in t:
j.join()

递归锁解决死锁问题

从上面一个例子来看,说明当任务拿到了递归锁,那么其他线程任务就只能等待,拿到递归锁的任务线程所有任务执行完毕后再争抢这把锁来让自己执行任务了。

递归锁:为了支持在同一线程中多次请求同一资源,python提供了“可重入锁”:threading.RLock。RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire。直到一个线程所有的acquire都被release,其他的线程才能获得资源。

4、同步条件

 import threading,time

 class Boss(threading.Thread):
def run(self):
print("Boss:Tonight we mast working to 11:00")
event.set()
print(event.isSet())
time.sleep(5)
print("Boss:ok! we can go home.")
print(event.isSet())
event.set() class Worker(threading.Thread):
def run(self):
event.wait()
print("Worker:Oh my god!")
time.sleep(1)
event.clear()
event.wait()
print("Worker:OhYeah!") if __name__ == "__main__":
event = threading.Event()
threads = []
for i in range(5):
threads.append(Worker())
threads.append(Boss())
for t in threads:
t.start()
for t in threads:
t.join()

同步条件例子

例子讲解:5个工人线程启动的时候,会监听等待一个事件,当老板线程启动了,时间被设定为True,5个工人线程收到事件后做出反映,然后清楚本次事件,再监听新的事件。

5、信号量

信号量是用来控制线程并发数的,BoundedSemaphore或Semaphonre管理一个内置的计数器,每当调用acquired()时-1,调用released()时+1

计数器不能小于0,当计数器为0时,acquire()将阻塞线程至同步锁定状态,知道其他线程调用released().

BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。

 import threading,time

 class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(3)
semaphore.release() if __name__ == "__main__":
semaphore = threading.Semaphore(5)
t = []
for i in range(100):
t.append(myThread())
for j in t:
j.start()

信号量例子

6、队列

队列的方法

 创建一个“队列”对象
import Queue
q = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。 将一个值放入队列中
q.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为
1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。 将一个值从队列中取出
q.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,
get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。 Python Queue模块有三种队列及构造函数:
1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize)
2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize)
3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize) 此包中的常用方法(q = Queue.Queue()):
q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作

队列有两种工作方式,一个是先进先出,一个是先进后出。大多数使用场景都是先进先出场景。

用队列来实现生产者消费者模型

 import time,random
import queue,threading q = queue.Queue() def Producer(name):
count = 0
while count<100:
print("making .....")
time.sleep(random.randrange(4))
q.put(count)
print("Producer %s has produced %s baozi.." % (name,count))
count += 1
print("ok....") def Consumer(name):
count = 0
while count < 100:
time.sleep(random.randrange(3))
if not q.empty():
data = q.get()
# q.task_done()
# q.join()
print(data)
print('\033[32;1mConsumer %s has eat %s baozi...\033[0m' % (name, data))
else:
print("-----no baozi anymore----")
count += 1 p1 = threading.Thread(target=Producer,args=("A",))
c1 = threading.Thread(target=Consumer,args=("B",)) p1.start()
c1.start()

吃包子

三、进程

1、进程的两种调用方式(和线程类似)

(1)、直接调用

 from multiprocessing import Process
import time def foo(name):
time.sleep(1)
print("hello",name,time.ctime()) if __name__=="__main__":
p_list=[]
for i in range(3):
p = Process(target=foo,args=('aaa',))
p_list.append(p)
p.start()
for i in p_list:
p.join()
print("end")

直接调用

(2)、类的继承方式调用

 from multiprocessing import Process
import time class MyProcess(Process):
def __init__(self,num):
super(MyProcess,self).__init__()
self.num=num def run(self):
time.sleep(1)
print("hello",self.num,time.ctime()) if __name__=="__main__":
p_list = []
for i in range(3):
p = MyProcess(i)
p.start()
p_list.append(p)
for p in p_list:
p.join() print("end")

继承方式调用

2、Process类的方法

构造方法:
Process([group [, target [, name [, args [, kwargs]]]]])
  group: 线程组,目前还没有实现,库引用中提示必须是None; 
  target: 要执行的方法; 
  name: 进程名; 
  args/kwargs: 要传入方法的参数。
实例方法:
  is_alive():返回进程是否在运行。
  join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
  start():进程准备就绪,等待CPU调度
  run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。
  terminate():不管任务是否完成,立即停止工作进程
属性:
  daemon:和线程的setDeamon功能一样
  name:进程名字。
  pid:进程号。

3、进程间通信

(1)进程队列Queue

注意:进程是大写的Queue模块,线程是小写的queue模块。

 from multiprocessing import Process,Queue

 def foo(q,n):
q.put(n*n+1)
print("son process",id(q)) if __name__=="__main__":
q = Queue()
print("main process",id(q)) for i in range(3):
p = Process(target=foo,args=(q,i))
p.start()
print(q.get())
print(q.get())
print(q.get())

Queue例子

(2)管道Pipe()

 from multiprocessing import Process,Pipe

 def foo(conn):
conn.send([12,{"name":"ptq"},"hello"])
response = conn.recv()
print("response:",response)
conn.close()
print("q_ID2:", id(conn)) if __name__=="__main__":
parent_conn,child_conn = Pipe()
print("q_ID1:", id(child_conn))
p1 = Process(target=foo,args=(child_conn,))
p1.start()
print("parent_conn",parent_conn.recv())
parent_conn.send("hello son process")
p1.join()

管道Pipe例子

(3)、共享内存Managers

 from multiprocessing import Process,Manager

 def foo(d,l,i):
d[i]=1
d['']=2
l.append(i)
print("son process:",id(d),id(l)) if __name__=="__main__":
with Manager() as manager:
d = manager.dict()
l = manager.list(range(5))
print("main process: ",id(d),id(l))
p_list = []
for i in range(10):
p = Process(target=foo,args=(d,l,i))
p.start()
p_list.append(p) for p in p_list:
p.join()

Managers例子

(4)、进程池

进程池内部维护一个进程序列,当使用时,择取进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池的两个方法:

apply   这个方法效果就是串行的效果,不管池子里面有多少个进程可用。都是一个进程一个进程运行。

apply_async

 from multiprocessing import Process,Pool
import time,os def Foo(i):
time.sleep(1)
print(i)
return i+100 def Bar(arg):#回调函数调用,参数是上一个函数的返回值
print(os.getpid())
print(os.getppid())
print("logger:",arg) if __name__== "__main__":
pool = Pool(5)
# Bar(1)
print("-----------------")
for i in range(10):
pool.apply_async(func=Foo,args=(i,),callback=Bar)#这里的callback是回调函数。 #这里是固定写法,变了就会报错
pool.close()
pool.join()
print("end")

进程池例子

python的进程与线程的更多相关文章

  1. Python的进程与线程--思维导图

    Python的进程与线程--思维导图

  2. Python创建进程、线程的两种方式

    代码创建进程和线程的两种方式 """ 定心丸:Python创建进程和线程的方式基本都是一致的,包括其中的调用方法等,学会一个 另一个自然也就会了. "" ...

  3. python之进程与线程

    什么是操作系统       可能很多人都会说,我们平时装的windows7 windows10都是操作系统,没错,他们都是操作系统.还有没有其他的? 想想我们使用的手机,Google公司的Androi ...

  4. python的进程与线程(二)

    线程 之前了解了操作系统的发展史,也知道了进程和线程的概念,归纳一下就是:         进程:本质上就是一段程序的运行过程(抽象的概念)         线程:最小的执行单元,是进程的实体     ...

  5. Python 9 进程,线程

    本节内容 python GIL全局解释器锁 线程 进程 Python GIL(Global Interpreter Lock) In CPython, the global interpreter l ...

  6. python之进程和线程2

    1  GIL全局解释器锁定义 定义:在一个线程拥有了解释器的访问权后,其他的所有线程都必须等待他释放解释器的访问权,即这些线程的下一条指令并不会互相影响. 缺点:多处理器退化为单处理器 优点:避免大量 ...

  7. python之进程和线程

    1 操作系统 为什么要有操作系统 ? 操作系统位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进程切换: 出现IO操作 固定时间 2 进程和线程的概念 进程就是一个程序 ...

  8. 《Python》进程收尾线程初识

    一.数据共享 from multiprocessing import Manager 把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机 ...

  9. Python基础进程和线程

    一 背景知识 进程的概念起源于操作系统,是操作系统最核心的概念. 进程是对正在运行程序的一个抽象,操作系统的其他所有内容都是围绕进程的概念展开的.所以想要真正了解进程,必须事先了解操作系统,egon介 ...

  10. Python中进程和线程的总体区别

    Num01–>线程 线程是操作系统中能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位. 一个线程指的是进程中一个单一顺序的控制流. 一个进程中可以并发多条线程,每条线程并行 ...

随机推荐

  1. Spring Boot(四):利用devtools实现热部署,改动代码自动生效

    一.前言 spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的功能就是自动应用代码更改到最新的App上面去.原理是在发现代码有更改之后,重新启动应用,但是速度比手动停止后 ...

  2. Bash编程的难点

    Bash作为一个编程语言,有很多奇怪的表达字符,有时候会让人感到很费解,其实,只要我们弄清楚bash面临的问题 就能够理解为啥要这么搞了,举个例子: 1.比较字符串"ab"和&qu ...

  3. 使用 OpCache 提升 PHP 性能

    使用 OpCache 提升 PHP 性能 wdd2007wdd2007 .6k 1月29日 发布 推荐 推荐 收藏 收藏,.3k 浏览 OpCache 通过对 opcode 的缓存和优化来提升 PHP ...

  4. CCNA2.0笔记_路由分类

    直连路由:当在路由器上配置了接口的IP地址,并且接口状态为up的时候,路由表中就出现直连路由项 静态路由:静态路由是由管理员手工配置的,是单向的. 默认路由:当路由器在路由表中找不到目标网络的路由条目 ...

  5. NGUI本地化

    之前在网上的NGUI本地化教程是基于老版本的了,现在用的3.7版本已经改了很多,以前的本地化教程有点不适用了. 1.资源: 本地化的txt文本起名叫做Chinese.txt,到resource目录下新 ...

  6. libubox-runqueue

    参考:libubox [4] - uloop runqueue ustream 任务队列是通过uloop定时器实现,把定时器超时时间设置为1,通过uloop事件循环来处理定时器就会处理任务队列中的ta ...

  7. JDK1.5中支持的 for循环的语法

    JDK1.5中支持的 for循环的语法 解答: for(type element : array) { System.out.println(element) } type 集合(不仅仅指Collec ...

  8. 如何获得<div id=”div1”>This is first layer</div>中的值?

    如何获得<div id=”div1”>This is first layer</div>中的值? 解答: <script> var div1=Document.ge ...

  9. 嵌入式驱动开发之dsp 算法优化vlib emcv---算法优化

    http://www.opencv.org.cn/forum.php?mod=forumdisplay&fid=9

  10. 安装tomcat出现failed to install tomcat6 service错误及解决方法(转载)

    安装安装版tomcat会出现failed to install tomcat6 service ,check your setting and permissio的概率是非常低的,但是最近楼主就老出现 ...