1 2 3 4

进程剩余部分和线程

1创建进程的2种方式

# 创建进程的2种 方式
from multiprocessing import Process
#方式一
def task():
    pass
p_obj = Process(target = task)
#告诉操作系统,让它 去创建一个子进程
p_obj.start()
#让主进程等待子进程结束后,在结束,并销毁
p_obj.join()
#方式二
class MyProcess(Process):
    def run(self):
        pass
p_obj = MyProcess()
#告诉操作系统,让他创建一个子进程
p_obj.start()
#让主进程 等待子进程结束后并销毁
p_obj.join()

2.子进程回收资源的2种方式

1.join让主进程等待子进程结束后,并回收子进程资源,主进程再结束并回收资源

2.主进程“正常结束”,子进程也和主进程一并被回收

from multiprocessing import Process
import time
def  task():
    print('start....')
    time.sleep(10)
    print('end...')
if __name__ == '__main__':

    obj = Process(target = task)
    obj.start()
    print('主进程')
    time.sleep(3)
    print('主程序结束')
    
    

2.1僵尸进程和孤儿进程

1.僵尸进程:(有坏处)

​ -在子进程结束后,主进程没有正常结束的,子进程的PID不会被回收;

​ 缺点:

​ -操作系统种的PID号是有限 的,如果子进程的PID无法正常回收,则会占用PID 号;

​ -资源浪费

​ -若PID号满了,则无法创建新的进程。

2.孤儿进程(没有坏处):

​ -在子进程没有结束时,主进程没有正常的结束,子进程的PID不会被回收;

​ -操作系统的优化机制(孤儿院)

​ -当主程序意外终止,操作系统的会检测是否有正在运行的子进程,会把放进孤儿院中,让操作系统帮你自动回收,

PID是操作系统给进程的一个编号,是 有限的,所以在进程结束需要回收。,

3.守护进程

定义:当主进程结束后,子进程必须结束,并回收。

​ -守护进程必须在守护进程必须在p.start()之前设置, p.daemon = True

rom multiprocessing import Process
import time
def task():
    print('start...')
    time.sleep(1000)
    print('end....')
if __name__ == '__main__':
    p = Process(target = task)
    #守护进程必须在p.start()之前设置
    p.daemon = True #将子进程设置为守护进程
    #告诉操作系统你开启了子进程
    p.start()

    time.sleep(1)
    print('主进程正在进行')
    >>>>>>>>>>>>>>>>>>>>>>>>>>>
 start...
主进程正在进行
Process finished with exit code 0
from multiprocessing import Process
import time
def demo(name):
    print(f'start...{name}')
    time.sleep(1000)
    print(f'end....{name}')
if __name__ == '__main__':
    p = Process(target = demo,args = ('童子军json',))
    #守护进程必须在p.start()之前设置
    p.daemon = True #将子进程设置为守护进程
    #告诉操作系统你开启了子进程
    p.start()

    time.sleep(1)
    print('主进程正在进行')
    >>>>>>>>>>>>>>>>>>>>>>>>>>
start...童子军json
主进程正在进行

Process finished with exit code 0

4.进程间的数据是隔离的

from multiprocessing import Process
import time
number = 10
def func():
    global number #声明的是全局的变量  下面的number+=10 是可以用的
    number +=10# 如果没有上面的global  这个是会报错
    print(number)

if __name__ == '__main__':
    obj = Process(target = func)
    obj.start()

    time.sleep(1)
    print(number) ## 这个是主进程的打印结果
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    20
	10

5.互斥锁

-互斥锁是一把锁,用来保证数据的读写安全。

data.json = {"number":1}

from multiprocessing import Process
from multiprocessing import Lock
import random
import time
import json
#抢票的例子
#1查看余票
def seach(name):
    #读取data.json文件中的数据
    with open('data.json','r',encoding = 'utf-8') as f:
        data_dic = json.load(f)
        print(f'用户[{name}]查看余票,余票还剩:[{data_dic.get("number")}]')

#2若有余票 够买成功,票数减少
def buy(name):
   with open('data.json','r',encoding = 'utf-8')  as f :
       data_dic = json.load(f)
        #进入这一步证明最先抢到票

   if data_dic.get('number') >0:


        data_dic['number'] -= 1
        time.sleep(random.randint(1,3))
        with open('data.json','w',encoding = 'utf-8') as f:
            json.dump(data_dic,f)
            print(f'用户[{name}],抢票成功')

   else:
        print(f'用户[{name}],抢票失败')

def run(name,lock):
    #假如1000个人都可以立马查看余票
    seach(name)
    lock.acquire()#加锁
    buy(name)
    lock.release()#释放锁

if __name__ == '__main__':
    lock = Lock()
    #开启多进程,实现并发、
    for line in range(10):

        p_obj = Process(target = run ,args = (f'jason{line}',lock))
        p_obj.start()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>这样操作的目地是在def buy哪里加一把锁,让最先进来的人得到 以后的都不允许在进入到这一步,第一个拿到锁以后,然后会释放,第二个进来的人,可以再用。
用户[jason0]查看余票,余票还剩:[1]
用户[jason2]查看余票,余票还剩:[1]
用户[jason1]查看余票,余票还剩:[1]
用户[jason3]查看余票,余票还剩:[1]
用户[jason6]查看余票,余票还剩:[1]
用户[jason4]查看余票,余票还剩:[1]
用户[jason7]查看余票,余票还剩:[1]
用户[jason5]查看余票,余票还剩:[1]
用户[jason8]查看余票,余票还剩:[1]
用户[jason9]查看余票,余票还剩:[1]
用户[jason0],抢票成功
用户[jason2],抢票失败
用户[jason1],抢票失败
用户[jason3],抢票失败
用户[jason6],抢票失败
用户[jason4],抢票失败
用户[jason7],抢票失败
用户[jason5],抢票失败
用户[jason8],抢票失败
用户[jason9],抢票失败

6.队列

-先进先出,先存放的数据 ,就先取出来,相当于一个第三方的管道,可以存放数据

-应用:可以让进程之间的数据进行交互

from multiprocessing import Queue #提供对列,先进先出
from multiprocessing import JoinableQueue  #基于Queue封装的队列,先进先出
import queue  #python内置的队列 先进先出

#第一种Queue
#Queue(5)指的是队列中只能存放4个数据
q_obj1 = Queue(4)
q_obj1.put('jsaon')
print('1')
q_obj1.put('abd')Queue
print('1')
q_obj1.put('dbdf')
print('1')
q_obj1.put('qwr')
print('1')
q_obj1.put('sean')  # 只要队列满了 就会进入堵塞
print('1')
>>>>>>>>>>>>>>>>>>>> #下面的这个只有4个1 打印 还有一个因为队列满了 就没有打印 但是也不会报错
1
1
1
1

q_obj1.put_nowait('sean')###用这个put_nowait 如果满了,是可以报错的
print('1')

#get:只要队列中有数据,就能获得数据,若没有则会进入阻塞
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())  ##实际只打印了4 个 还有一个没有打印  但是也不会报错
>>>>>>>>>>>>>>>>>>>>>>>>>>>
jsaon
abd
dbdf
qwr

#get_nowait:如果对列中没有数据,则会报错
print(q_obj1.get_nowait())


针对于put.nowait和get.nowait 针对第二种和第三种都是适用的

第二种 
q_obj1 = JoinableQueue(4)

q_obj1.put('jsaon')

print('1')
q_obj1.put('abd')
print('1')
q_obj1.put('dbdf')
print('1')
q_obj1.put('qwr')
print('1')
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
>>>>>>>>>>>>>>>>>>>>>>>
1
1
1
1
jsaon
abd
dbdf
qwr

第三种
q_obj1 = queue.Queue(4)

q_obj1.put('jsaon')

print('1')
q_obj1.put('abd')
print('1')
q_obj1.put('dbdf')
print('1')
q_obj1.put('qwr')
print('1')
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())
print(q_obj1.get())


7.进程间实现通信(IPC机制)

from multiprocessing import Process
from multiprocessing import JoinableQueue
import time
def task1(q):
    x = 100
    q.put(x)
    print('添加数据')

    time.sleep(3)
    print(q.get())##因为有时间的延迟 ,所以这个队列的接收的数据会延后


def task2(q):
    res = q.get()
    print(f'获取的数据是{res}')####这个一步先获取数据
    q.put(9527)

if __name__ == '__main__':
    #产生列队
    q= JoinableQueue(10)
    #产生2个不同子进程
    p1 = Process(target = task1,args = (q,))
    p2 = Process(target = task2,args = (q,))
    p1.start()
    p2.start()
    print('主进程进行中')
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
主进程进行中
添加数据
获取的数据是100
9527

8.生产者和消费者

-生产者:生产数据

-消费者:使用数据

-出现的问题:

​ 生产的数据跟不上使用数据的人

​ 使用数据的速度跟不上使用数据的速度

下面的这个例子就是根据队列来实现:解决供需不平衡的问题
from multiprocessing import JoinableQueue
from multiprocessing import Process
import time
import random
#生产者 生产数据---->队列
def producer(name,food,q):
    msg = f'{name}生产了{food}食物'
    #生产一个食物就添加到队列中
    q.put(food)
    print(msg)

#消费者,使用数据
def customer(name,q):
    while True:
        try:
            time.sleep(random.randint(1,2))
            food = q.get_nowait()#若报错,则跳出循环
            msg = f'{name}吃了{food}食物'
            print(msg)

        except Exception:
            break

if __name__ == '__main__':
    q = JoinableQueue()
    #创建2 个生产者
    for line in range(10):
        p1 = Process(target = producer,args =('tank',f'pig饲料{line}',q))
        p1.start()

        #创建2个消费者
        c1 = Process(target = customer,args = ('jason',q))
        c2 = Process(target = customer,args = ('sean',q))
        c1.start()
        c2.start()
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
tank生产了pig饲料1食物
tank生产了pig饲料0食物
tank生产了pig饲料4食物
tank生产了pig饲料2食物
tank生产了pig饲料3食物
tank生产了pig饲料5食物
tank生产了pig饲料6食物
tank生产了pig饲料8食物
tank生产了pig饲料7食物
tank生产了pig饲料9食物
sean吃了pig饲料1食物
jason吃了pig饲料0食物
sean吃了pig饲料4食物
sean吃了pig饲料2食物
jason吃了pig饲料3食物
jason吃了pig饲料5食物
sean吃了pig饲料6食物
sean吃了pig饲料8食物
sean吃了pig饲料7食物
jason吃了pig饲料9食物

9.线程

1.什么是线程?

​ 进程:资源单位

​ 线程:执行单位

​ 线程和进程都是虚拟的概念,为了更好表达某种事物

​ 注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者

2.为什么使用线程?

​ 节约资源的占用

​ -开启进程:

​ 1.会产生一个内存空间,申请一块资源

​ 2.会自带一个主线程

​ 3.开启子进程的速度要比开启子线程的速度慢

​ -开启线程

​ 1.一个进程可以开启多个线程,从进程的内存空间中申请执行单位;

​ 2.节约资源

​ -开启三个进程:

​ -占用三分内存资源

​ -开启三个线程

​ -从一个内存资源中,申请三个小的执行单位

​ -IO密集型 多线程

​ -计算密集型 多进程

注意:进程和进程之间的数据是隔离的,线程和线程之间的数据是共享的

from threading import Thread
import time
#启动线程的方式一
#任务一
number = 1000
def task():
    global number
    number = 100
    print('start...')
    time.sleep(1)
    print('end...')
if __name__ == '__main__':
    #开启一个子线程
    t = Thread(target = task)
    t.start()
    # t.join()
    print('主进程(主线程)')
    print(number)
>>>>>>>>>>>>>>>>>>>>
start...
主进程(主线程)
100
end...



from threading import Thread
from multiprocessing import Process
import os
def work():
    print('hello',os.getpid())

if __name__ == '__main__':
    #主进程下下面开启的多个线程,每个线程都革命主进程的pid一样
    t1 = Thread(target = work)
    t2 = Thread(target = work)
    t1.start()
    t2.start()
    print('主线程pid',os.getpid())

    #开多个进程 每个进程有不同的pid
    p1 = Process(target = work)
    p2 = Process(target = work)
    p1.start()
    p2.start()
    print('主进程pid',os.getpid())
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
hello 208580
hello 208580
主线程pid 208580
主进程pid 208580
hello 208688
hello 68828


9.3线程的守护进程

#启动线程的方式二
from threading import Thread
import time
class MyThread(Thread):
    def run(self):
        print('start...')
        time.sleep(2)
        print('end...')

if __name__ == '__main__':
    t = MyThread()
    t.daemon = True #当主进程结束后,子进程必须结束,并回收。
    t.start()
    print('主进程(主线程)...')
>>>>>>>>>>>>>>>>>>>>>>>>>>>
start...
主进程(主线程)...

Process finished with exit code 0

#启动线程的方式二
from threading import current_thread
from threading import Thread
import time
def task():

    print(f'start...{current_thread().name}')   #打印线程的名字
    time.sleep(2)
    print(f'end...{current_thread().name}')

if __name__ == '__main__':
    for line in range(10):
        t = Thread(target = task)
        t.daemon = True #当主进程结束后,子进程必须结束,并回收。
        t.start()
        print(f'主进程(主线程)...{current_thread().name}')
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start...Thread-1
主进程(主线程)...MainThread
start...Thread-2
主进程(主线程)...MainThread
start...Thread-3
主进程(主线程)...MainThread
start...Thread-4
主进程(主线程)...MainThread
start...Thread-5
主进程(主线程)...MainThread
start...Thread-6
主进程(主线程)...MainThread
start...Thread-7
主进程(主线程)...MainThread
start...Thread-8
主进程(主线程)...MainThread
start...Thread-9
主进程(主线程)...MainThread
start...Thread-10
主进程(主线程)...MainThread

Process finished with exit code 0



9.4线程的互斥锁

from threading import Lock
from threading import Thread
import time
lock = Lock()
number = 100
#开启10个线程 对一个数据进行修改
def task():
    global number
    lock.acquire()##这个是加锁
    number -= 1
    time.sleep(1)

    lock.release()###这个是去锁

if __name__ == '__main__':
    list = []
    for line in range(4):
        t = Thread(target = task)
        t.start()
        list.append(t)

    for t in list:
        t.join()

    print(number)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>
94

9.5线程池

-线程池是用来限制创建的线程数

from concurrent.futures import ThreadPoolExecutor
import time
#pool只能创建100个线程
pool = ThreadPoolExecutor(100)
def task(line):
    a = time.time()
    print(line)
    time.sleep(10)
    b = time.time()
    print(b -a)

if __name__ == '__main__':
    for line in range(1000):
        pool.submit(task,line)

posted @ 2019-12-10 05:52  ^更上一层楼$  阅读(125)  评论(0编辑  收藏  举报