Day35 python基础--并发编程基础4

一,进程的数据共享机制--Manager模块

  1.把所有实现了数据共享的比较便捷的类都重新封装了一遍

  2.并且在原有的multiprocessing的基础上,增加了新的机制list、dict

  3.支持的数据类型非常有限

  4.list、dict都不是数据安全的,需要自行加锁来保证数据安全

  5.工作中一般是通过第三方工具实现进程间的数据共享

from multiprocessing import Manager,Process,Lock
def work(d,lock):
    with lock:
    # lock.acquire()
        d['count'] -= 1      #操作数据是一个取值赋值过程
    # lock.release()

if __name__ == '__main__':
    lock = Lock()
    m = Manager()      #with Manager() as m: 
    dic = m.dict({'count':100})
    p_1 = []
    for i in range(100):
        p = Process(target=work,args=(dic,lock))
        p_1.append(p)
        p.start()
    for p in p_1:
        p.join()
    print(dic)

二,进程的回调函数

  1.当子进程执行完毕之后执行callback函数

  2.子进程的返回值会作为callback的参数

  3.回调函数在主进程执行

  应用场景:

    1.使用主进程统一的获取结果,这样的化在进程之间没有数据隔离

    2.多个子进程所做的事情是比较长时间的,而主进程中回调函数的执行速度都比较快

      子进程中做网络访问,主进程处理网页的结果

      子进程有大量的计算要去做,回调函数等待结果做简单处理

def func(i):
    print('第一个任务',os.getpid())
    return '*'*i,
def call_back(res):  #只能接受一个参数,可以*res;本体是args*,传多个参数会聚合为一个元组
   print('回调函数:',os.getpid()) 
  print('ret-->',res) if __name__ == '__main__': p = Pool()
   print('主进程:',os.getpid()) p.apply_async(func,args
=(1,),callback=call_back) p.close() p.join()
#实例一:
url_lst = ['http://www.baidu.com',
           'http://www.souhu.com',
           'http://www.sogou.com',
           'http://www.4399.com',
           'http://www.cnblogs.com']
import re
from multiprocessing import Pool
from urllib.request import urlopen

def get_url(url):
    response = urlopen(url)
    ret = re.search('www.(.*?).com',url)
    print('%s finish'%ret.group(1))
    return ret.group(1),response.read()

def call(content):
    url,con = content
    with open(url+'.html','wb') as f:
        f.write(con)

if __name__ == '__main__':
    p = Pool()
    for url in url_lst:
        p.apply_async(get_url,args=(url,),callback=call)
    p.close()
    p.join()
#实例二
import re
from multiprocessing import Pool
from urllib.request import urlopen

def get_url(url):
    response = urlopen(url)
    ret = re.search('www.(.*?).com',url)
    print('%s finish'%ret.group(1))
    return ret.group(1),response.read()

def call(content):
    url,con = content
    with open(url+'.html','wb') as f:
        f.write(con)

if __name__ == '__main__':
    p = Pool()
    p_lst = []
    for url in url_lst:
        ret = p.apply_async(get_url,args=(url,))  #ret是一个内存地址
        p_lst.append(ret)
    for ret in p_lst:
        call(ret.get())

三,线程

  线程vs进程:

    进程的概念:

      1.计算机中最小的资源分配单位

      2.进程对于操作系统来说还是有一定负担的

      3.创建一个进程,操作系统要分配的资源大致有:

        代码,数据,文件

    线程的概念

      1.轻量级

      2.没有属于自己的进程资源

      3.为什么要有线程

           一条线程只负责执行代码,没有自己独立的代码,变量,文件资源

           解决高并发的情况下,资源有限的问题

      4.什么是线程:

        线程是计算机中被cpu调度的最小单位

        你的计算机当中的cpu都是执行的线程中的代码

      5.线程和进程之间的关系

        每一个进程中都有至少一条线程在工作

      6.线程的特点

        同一个进程中的所有线程的资源时共享的

        轻量级:没有自己的资源

      7.进程和线程之间的区别

        占用的资源,线程之间共享进程内的资源,但是线程内的局部变量还是要占用资源

        调度的效率:线程是计算机中被cpu调度的最小单位,调度速度快,开销小

        资源是否共享:线程共享进程内的资源

        可以并发执行

      8.通用问题

        java,c++,c#在一个进程中的多个线程能够并行

        为什么python(c)中一个进程中的多个线程不能并行?

          1.python是一个解释型的语言

          2.cpython解释器,内部有一把全局解释器(GIL)

            所以线程不能充分的利用多核

            同一时刻同一个进程中的线程只有一个能被cpu执行

          3.GIL锁:确实是限制了程序效率

          4.GIL目前是能够帮助你在线程的切换中提高效率

          5.asyncio模块

      9.python的劣势,关于GIL的历史遗留问题

        python不能实现,cpu利用率,极端的高计算型,需要多线程多核cpu高利用需求

        解决办法:多进程,换一个解释器

#线程的代码实现:thread、threading
#效率对比
import os
import time
from threading import Thread
from multiprocessing import Process
def func(i):
    # time.sleep(1)
    print('子线程%s'%i,os.getpid())
#多线程
# print('主进程',os.getpid())
if __name__ == '__main__':
    t_lst = []
    start = time.time()
    for i in range(100):
        t = Thread(target=func,args=(i,))
        t.start()
        t_lst.append(t)
    for t in t_lst:
        t.join()
    tt = time.time() - start

# if __name__ == '__main__':
    start = time.time()
    p_lst = []
    for i in range(100):
        p = Process(target=func,args=(i,))
        p.start()
        p_lst.append(p)
    for p in p_lst:
        p.join()
    print(time.time() - start)
    print(tt)
# 多线程的数据共享
import os
import time
from threading import Thread
from multiprocessing import Process
num = 100
def func():
    global num
    num -= 1

if __name__ == '__main__':
    t_lst = []
    for i in range(100):
        t = Thread(target=func)
        t.start()
        t_lst.append(t)
    for t in t_lst:
        t.join()
    print(num)
#守护线程
#守护线程是在主线程结束之后,还等待了子线程执行结束才结束
#主线程结束,意味着主进程结束
#主线程等待所有的线程结束
#主线程结束之后,守护线程随着主进程的结束自然结束了
import time
from threading import Thread
def func1():
    while True:
        time.sleep(0.5)
        print(123)
def func2():
    print('func2 start')
    time.sleep(3)
    print('func end')

t1 = Thread(target=func1)
t2 = Thread(target=func2)
t1.setDaemon(True)
t1.start()
t2.start()
print('主线程的代码结束')
#Thread实例对象的方法
  # isAlive(): 返回线程是否活动的。
  # getName(): 返回线程名。
  # setName(): 设置线程名。

threading模块提供的一些方法:
  # threading.currentThread(): 返回当前的线程变量。
  # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

from threading import Thread
import threading
from multiprocessing import Process
import os

def work():
    import time
    time.sleep(3)
    print(threading.current_thread().getName())


if __name__ == '__main__':
    #在主进程下开启线程
    t=Thread(target=work)
    t.start()

    print(threading.current_thread().getName())
    print(threading.current_thread()) #主线程
    print(threading.enumerate()) #连同主线程在内有两个运行的线程
    print(threading.active_count())
    print('主线程/主进程')

    '''
    打印结果:
    MainThread
    <_MainThread(MainThread, started 140735268892672)>
    [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>]
    主线程/主进程
    Thread-1
    '''

 四,总结

#线程
#线程和进程之间的关系
    #每个进程内都有一个线程
    #线程是不能独立存在的
#线程和进程之间的区别
    #同一个进程中线程之间的数据是共享的
    #进程之间的数据是隔离的
    #线程是由cpu执行的最小单位
        #操作系统调度
    #进程是计算机中最小的资源分配单位
#python
    #GIL锁 全局解释器锁 全局锁
    #锁线程:同一时刻同一进程只会有一个线程访问cpu
        #锁的是线程而不是数据
    #当程序是高IO形的 多线程
    #当程序是高计算(cpu)型 多进程
        #多进程数的范围:cpu*1 ~ cpu*2

#threading
#Thread
    #守护线程:主线程结束之后才结束

#socketserver IO多路复用 + 多线程
#框架 并发的效果:多线程,协程的概念 flask
#爬虫:线程池 协程

      

      

原文地址:https://www.cnblogs.com/lianyeah/p/9692515.html