把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end
旋转立方体
旋转立方体end

掌握并发编程1

一、操作系统介绍

  1.1、什么是操作系统

    操作系统是一个协调、管理和控制计算机硬件资源和软件资源的控制程序。

    1、操作系统的内核

      运行于内核态,管理硬件资源

    2、系统调用

      运行于用户态,为程序员写的应用程序提供系统调用接口。

  1.2、操作系统的功能

    1、隐藏了复杂的硬件调用接口,为程序员提供调用硬件资源的更好、更简单、更清晰的模型(系统调用接口)

      例如:用操作文件的方式,代替关于磁盘读写的操作

    2、将应用程序对硬件资源的请求变得有序化

  1.3、操作系统与普通软件的区别

    1、操作系统由硬件保护,不能被用户修改

    2、操作系统是一个大型、复杂、长寿的软件

      大型:Windows和Linux仅内核源码就有500多万行,用户程序,如GUI、库、以及基本应用软件(如Windows explorer 等)很容易再扩充10到20倍。

      长寿:操作系统一旦完成,不会轻易替换,而是在原有基础上改进 

  1.4、操作系统发展史

    1.4.1、第一代计算机:真空管和穿孔卡片

      特点:

        1、没有操作系统概念

        2、所有的程序设计都是直接操控硬件

      优点:
        1、程序员在申请的时间段内独享整个资源,可以即时的调试自己的程序(随时处理bug)

      缺点:

        1、浪费计算机资源,一个时间段内只有一个人使用

        2、同一时刻只有一个程序在内存中运行,多个程序的执行是串行的

    1.4.2、第二代计算机:晶体管和批处理系统

      特点:

        1、设计人员、生产人员、操作人员、程序人员和维护人员直接有了明确的分工,计算机被所在专用空调房间中,由专业操作人员运行。

        2、有了操作系统的概念

        3、有了程序设计语言。将FORTRAN语言或汇编语言写在纸上,然后穿孔打成卡片,将多个人的卡片盒拿到输入室,由操作人员操作计算机统一运算,结果输出到磁带上。

      优点:
        1、批处理,节省了机时

      缺点:

        1、整个流程需要人为参与控制,不停运输磁带
        2、计算过程仍然是串行

        3、执行的程序被统一规划到一批作业中,无法及时调试程序,影响了开发效率。

    1.4.3、第三代计算机:集成电路芯片和多道程序设计

        多道技术:用多路复用的方法控制多个程序有序的竞争或共享一个资源(如CPU)。

        多路复用:

          1、空间上的复用:将内存分为几个部分,每个部分放入一个程序,这样同一时间内存中就有了多道程序
          2、时间上的复用:当一个程序在等待 I/O 时,另一个程序可以使用CPU,让CPU的利用率接近百分百。一个程序长时间占用CPU也会被操作系统自动切换。

        分时操作系统:多个联机终端+多道技术

    1.4.4、个人计算机

          

二、进程理论

  2.1、什么是进程
    正在进行的一个过程或一个任务,由CPU执行。

  2.2、进程与程序的区别

    程序是一堆代码,进程是程序的运行过程

  2.3、并发与并行
    1、并发:

      伪并行,由单个CPU+多道技术即可实现

    2、并行:
      同时运行,需要具备多个CPU

  2.4、进程的层次结构:
    1、Linux:所有进程以 init 为根,组成树形结构,父子进程公用一个进程组。

    2、Windows:没有进程层次概念,所有进程地位相同。

  2.5、进程的状态:

    阻塞态、运行态、就绪态

    进程在逻辑上无法运行的两种原因:
      1、自身原因,遇到 I/O 阻塞,让出CPU执行其他程序

      2、操作系统原因,一个进程占用时间过多,或者优先级的原因,让出CPU。

 

三、开启进程的两种方式

  3.1、multiprocessing 模块

    功能:开启子进程,并在子进程中执行定制的任务。提供了Process、Queue、Pipe、Lock等组件

  3,2、Process 类

    由该类实例化的到的对象,可用来开启一个子进程

    3.2.1、参数

      group        参数未使用,始终为None

      target        表示调用对象,即子进程要执行的任务

      args          表示调用对象的位置参数,写作元组形式。

      kargs        表示调用对象的字典.

      name        表示子进程名字

    3.2.2、方法

      p.start()    启动进程,调用该子进程中的 p.run()

      p.run()        进程启动运行的方法,正是它去调用 target 指定的函数。

      p.terminate()    强制终止进程 p,不会进行任何清理操作,如果 p 创建了子进程,该进程就成了僵尸进程。如果p保留了锁,也不会被释放,而成为死锁。

      p.is_alive()    判断 p 是否仍然运行

      p.join([timeout])  主线程等待 p 终止,timeout 是可选的超时时间

    3.2.3、属性

      p.deamon   默认值为 False,如果设为 True,代表 p 为后台运行的守护进程,当 p 的父进程终止时,p 也随之终止。设定为True后,p 还不能创建自己

              的新进程,必须在 p.start() 之前设置。

      p.name    进程的名称

      p.pid      进程的端口地址

  3.3、Process 的使用

    注意:在 Windows 中 Process() 必须放到 if __name__ == '__main__': 下

    1、

import time
import random
from multiprocessing import Process


def study(name):
    print('%s study' % name)
    time.sleep(random.randrange(1, 5))
    print('%s study end' % name)


if __name__ == '__main__':
    p1 = Process(target=study, args=('a',))
    p2 = Process(target=study, args=('b',))
    p3 = Process(target=study, args=('c',))

    p1.start()
    p2.start()
    p3.start()
    print('')
    

 

    2、

import time
import random
from multiprocessing import Process


class Study(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s study' % self.name)
        time.sleep(random.randrange(1, 5))
        print('%s study end' % self.name)


if __name__ == '__main__':
    p1 = Study('a')
    p2 = Study('b')
    p3 = Study('c')
    
    p1.start()
    p2.start()
    p3.start()   
    print('')
    

 

 

四、join方法

  4.1、process 对象的 join 方法

    作用:如果主进程的任务在执行到某一阶段时,需要等待子进程执行完毕后才能继续执行,就需要有一种机制能够让主进程检测子进程是否运行完毕,

       在子进程执行完毕后才继续执行,否则一直在原地阻塞。

from multiprocessing import Process
import time
import random
import os


def task():
    print('%s is studying' % os.getpid())
    time.sleep(random.randrange(1, 3))
    print('%s is sleeping' % os.getpid())

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('')

 

 

五、守护进程

  5.1、特点:

    1、守护进程会在主进程代码结束后终止
    2、守护进程内无法再开启子进程,否则抛出异常

  5.2、

from multiprocessing import Process
import time
import random

def task(name): print('%s is study' % name) time.sleep(random.randrange(1, 3)) print('%s is sleeping' % name) if __name__ == '__main__': p = Process(target=task, args=('a',)) p.daemon = True p.start() print('')

 

  

 六、互斥锁

  6.1、进程之间数据不共享,但是共享同一套文件系统,也由此带来了竞争,导致输出混乱。

    锁必须在主进程中产生,交给子进程使用。

    互斥锁特点:能将任务中某一段代码串行。

    1、并发运行,竞争同一终端导致打印错乱

from multiprocessing import Process
import os, time


def work():
    print('%s is running' %os.getpid())
    time.sleep(2)
    print('%s is done' %os.getpid())


if __name__ == '__main__':
    for i in range(3):
        p = Process(target=work)
        p.start()

 

    2、加锁后变成串行,牺牲了运行效率,但避免了竞争

def work(mutex):
    mutex.acquire()
    print('%s is running' %os.getpid())
    time.sleep(2)
    print('%s is done' %os.getpid())
    mutex.release()


if __name__ == '__main__':
    mutex = Lock()
    for i in range(3):
        p = Process(target=work, args=(mutex,))
        p.start()

 

   6.2、模拟抢票练习

    1、在执行文件目录下创建名为 'data.txt' 的文件,用 json 的字典格式写入 {"ticket": 1}

    2、并发运行,效率高,但竞争写同一文件,数据写入错乱,一张票10个人都抢到

from multiprocessing import Process
import time
import json


#查票
def search(i):
    with open('data.txt', 'r', encoding='utf-8') as f:
        data = f.read()
    ticket_num = json.loads(data)
    print('查询余票为:%s' % ticket_num.get('ticket'))
#买票
def buy(i):
    with open('data.txt', 'r', encoding='utf-8') as f:
        data = f.read()
    ticket_num = json.loads(data)
    time.sleep(3)
    if ticket_num.get('ticket') > 0:
        ticket_num['ticket'] -= 1
        with open('data', 'w', encoding='utf-8') as f:
            json.dump(ticket_num, f)
            f.flush()
        print('%s用户抢票成功' % i)
    else:
        print('没票了')

def run(i):
    search(i)
    buy(i)

if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=(i,))
        p.start()

    3、加锁处理,购票行为由并发变为串行,牺牲运行效率,保证了数据安全。

from multiprocessing import Process, Lock
import json
import time


def check():
    with open('data.txt', 'r', encoding='utf-8') as f:
        dict = json.load(f)
        ticket_num = dict['ticket']
        print('还剩%s张票' % ticket_num)

def buy(i):
    with open('data.txt', 'r', encoding='utf-8') as f:
        dict = json.load(f)
        ticket_num = dict['ticket']
        time.sleep(1)
    if ticket_num > 0:
        dict['ticket'] -= 1
        with open ('data.txt', 'w', encoding='utf-8') as f:
            json.dump(dict, f)
            f.flush()
        print('用户%s抢票成功' % i)
    else:
        print('余票不足')

def run(i, mutex):
    check()
    mutex.acquire()
    buy(i)
    mutex.release()

if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=run, args=(i, mutex))
        p.start()

 


    

  

posted @ 2019-08-13 00:02  远翔、  阅读(133)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end