精华内容
下载资源
问答
  • 消息队列是进程间通信,它是由操作系统维护以字节序列为基本单位间接通信机制,它提供了一个进程向另一个进程发送一个带类型数据块方法。 我们知道用管道来实现进程间通信机制是进程利用管道...

    首先说一下什么是消息队列。消息队列是进程间通信的一种,它是由操作系统维护的以字节序列为基本单位的间接通信机制,它提供了一个进程向另一个进程发送一个带类型的数据块的方法。
    我们知道用管道来实现进程间通信的机制是两个进程利用管道文件来实现数据交流,那么消息队列与管道有什么区别呢?
    首先看一下管道通信机制的模型:
    这里写图片描述
    然后消息队列通信模型:
    这里写图片描述
    从上面图中可看出两者有着本质的区别。那么两个进程怎么用消息队列进行通信呢?
    首先介绍一个函数——ftok函数
    先给出函数原型:key_t ftok(const char *path, int id);
    消息队列、共享内存和信号量三种进程间通信方式我们称为XSI IPC,当我们调用三种IPC的get函数创造一个IPC结构(比如消息队列)时,会返回相应的IPC标识符,然后我们就能用这个标识符对这个IPC结构进行操作,完成进程间通信,但是这个IPC标识符是这个IPC结构的内部名,我们在一个进程中创建一个IPC结构后另一个进程如何也连接到这个IPC结构呢?这就需要使用到“键”这个外部名了,先来看消息队列的结构:
    这里写图片描述
    结构的第一个成员是结构体类型,再深入这个结构体:
    这里写图片描述
    可以观察到,第一个成员就是key——键。
    再来看消息队列的get函数原型:
    int msgget(key_t key, int msgflg);
    这里的第一个参数就是key,这个函数在一个进程中正是根据这里的key值创建相应的消息队列,返回消息队列的标识符,而另一个进程只要得到相同的key值就可以用msgget函数得到想要的消息队列。
    而ftok函数正是根据两个参数创建一个“键”并返回,只要两个参数相同,返回的“键”也相同(关于ftok函数创建key的具体过程在《UNIX环境高级编程》的第15章有具体论述)。第一个参数表示路径名,第二个参数表示一个ID,两个参数可以任意给。
    msgget函数的第二个参数由9个权限标志构成,其用法与创建文件时使用的mode模式一样,通常我们使用到IPC_CREAT和IPC_EXCL两个权限标志,IPC_CREAT表示如果无则创建返回,有则直接返回;IPC_EXCL表示无则创建返回,有则报错。一般在创建消息队列时将两者合在一起使用,即IPC_CREAT | IPC_EXCL,这样就可以保证得到一个全新的消息队列。

    如果要删除消息队列可以用msgctl函数,当然这个函数的功能不止删除,这是一个控制函数,其原型为:int msgctl(int msgid, int cmd, struct msqid_ds *buf);
    返回值:若成功返回0,失败返回-1。
    参数:msgid:由msgget函数返回的消息队列标识符
    cmd:将要采取的动作,有三个值,删除消息队列用IPC_RMID。
    buf:删除时传入0。

    向消息队列中传入“消息”可用msgsnd函数:
    int msgsnd(int msgid, const void * msgp, size_t msgsz, int msgflg);
    返回值:成功返回0,失败返回-1。
    参数:msgid:消息队列表示符。
    msgp:指向要发送的消息的指针。
    msgsz:要发送消息的长度,这个长度不包含保存消息类型的那个长整型。
    msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情。msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误。

    从消息队列中获取消息可用msgrcv函数:
    ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtype, int msgflg);
    返回值:成功返回实际放到接收缓冲区里去的字符个数,失败返回-1。
    msgid:消息队列id。
    msgp:接收消息的缓冲区。
    msgsz:要获取的消息长度,不包含消息中的类型长度。
    msgtype:要接收的消息的类型。
    msgflg:控制着队列中没有想要类型的消息可供接收时将要发生的事。

    发送的消息的参考结构:

    struct msgbuf
    {
        logn mtype;
        char mtext[1];
    }

    其中mtype表示消息的类型,mtext表示要发送的消息,可任意指定。
    消息队列的结构模型:
    这里写图片描述
    每个消息的最⼤大⻓长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。
    特性:1、发送带类型数据块。
    2、是全双工的,可双向通信。
    3、生命周期随内核,必须显式删除。

    用消息队列实现两个进程间对话:
    Makefile文件:

    .PHONY : all
    all : server client
    
    server : server.c comm.c
        gcc -o server server.c comm.c
    
    client : client.c comm.c
        gcc -o client client.c comm.c
    
    .PHONY : clean
    clean :
        rm -f server client

    comm.h文件:

    #ifndef _COMM_H_
    #define _COMM_H_
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    #include <string.h>
    #include <strings.h>
    
    #define PATHNAME "."
    #define PROJ_ID 0x6666
    #define SERVER_TYPE 1
    #define CLIENT_TYPE 2
    
    
    struct mymsg
    {
        long mtype;
        char mtext[1024];
    };
    
    int CreatMsgQueue();
    int GetMsgQueue();
    int DelQueue(int msgid);
    int SendMsg(int msgid, char *buf, long mtype);
    ssize_t RecMsg(int msgid, char *buf, long mtype);
    
    
    
    #endif //__COMM_H_

    comm.c文件

    #include "comm.h"
    
    static int _GetCommMsgQueue(int flags)
    {
        key_t _key = ftok(PATHNAME, PROJ_ID);
        if(_key < 0)
        {
            perror("ftok");
            return -1;    
        }
        int msgid = msgget(_key, flags);
        if(msgid < 0)
        {
            printf("msgget\n");
        }
        return msgid;
    }
    int CreatMsgQueue()
    {
        return _GetCommMsgQueue(IPC_CREAT|IPC_EXCL|0666);
    }
    
    int GetMsgQueue()
    {
        return _GetCommMsgQueue(IPC_CREAT);
    }
    
    int DelQueue(int msgid)
    {
        return msgctl(msgid, IPC_RMID, NULL);
    }
    
    int SendMsg(int msgid, char *buf, long mtype)
    {
        assert(NULL != buf);
        struct mymsg msg;
        msg.mtype = mtype;
        strcpy(msg.mtext, buf);
        return msgsnd(msgid, (void*)&msg, sizeof(msg.mtext), 0);
    }
    
    ssize_t RecMsg(int msgid, char *buf, long mtype)
    {
        assert(NULL != buf);
        struct mymsg msg;
        int msglen = msgrcv(msgid, (void*)&msg, sizeof(msg.mtext), mtype, 0);
        if(msglen < 0)
        {
            perror("msgrcv");
            return -1;
        }
        strcpy(buf, msg.mtext);
        return msglen;
    }

    server.c文件:

    #include "comm.h"
    
    int main()
    {
        char buf[1024] = { 0 };
        int msgid = GetMsgQueue();
        int msglen = 0;
        if(msgid < 0)
            exit(EXIT_FAILURE);
        while(1)
        {
            if((msglen = RecMsg(msgid, buf, CLIENT_TYPE)) < 0)
                break;
            buf[msglen] = 0;
            write(1, "client:>", strlen("client:>"));
            write(1, buf, strlen(buf));
            if(strcmp(buf, "quit\n") == 0)
                break;
            write(1, "server:>", strlen("server:>"));
            if((msglen = read(0, buf, sizeof(buf))) < 0)
                break;
            buf[msglen] = 0;
            if(SendMsg(msgid, buf, SERVER_TYPE) < 0)
                break;
            if(strcmp(buf, "quit\n") == 0)
                break;
        }
        DelQueue(msgid);
    
        return 0;
    }

    client.c文件

    #include "comm.h"
    
    int main()
    {
        char buf[1024] = { 0 };
        int msgid = CreatMsgQueue();
        int msglen = 0;
        if(msgid < 0)
            exit(EXIT_FAILURE);
        while(1)
        {
            write(1, "client:>", strlen("client:>"));
            if((msglen = read(0, buf, sizeof(buf))) < 0)
                break;
            buf[msglen] = 0;
            if(SendMsg(msgid, buf, CLIENT_TYPE) < 0)
                break;
            if(strcmp(buf, "quit\n") == 0)
                break;
            if((msglen = RecMsg(msgid, buf, SERVER_TYPE)) < 0)
                break;
            buf[msglen] = 0;
            if(strcasecmp(buf, "quit\n") == 0)
                break;
            write(1, "server:>", strlen("server:>"));
            write(1, buf, strlen(buf));
        }
    
        return 0;
    }

    代码运行图:
    这里写图片描述

    展开全文
  • 消息队列的基本操作

    2020-01-08 21:05:04
    队列是先进先出(FIFO)存储数据结构 在进程中我们了解到,进程之间是不可以共享数据,那我们生活中要打开微信给朋友发一张图库图片,当图库打开就有了进程,那么这进程之间该如何传递数据呢?这时...

    什么是队列

    队列是一种先进先出(FIFO)的存储数据结构
    在这里插入图片描述
    进程中我们了解到,两个进程之间是不可以共享数据的,那我们生活中要打开微信给朋友发一张图库的图片,当图库打开就有了进程,那么这两个进程之间该如何传递数据呢?这时两个进程之间就要有个介质在这两个进程之间传递,在第一进程中写数据,到第二进程中读数据以队列为基础通过使用multiprocesing模块的Queue就可以实现进程之间的数据共享,
    Queue本身是一个消息队列程序

    队列的创建

    我们知道队列使用multiprocesing模块的Queue,用代码实现一下

    import multiprocessing
    #定义消息队列
    #如果不指定队列长度,则默认为最大,如果指定了消息队列的大小,则消息队列就有上限控制
    #此处的Queue(3)指的是放入3条消息
    queue=multiprocessing.Queue(3)
    #queue.put(值)向消息队列中放入内容
    #put的值几乎可以是任意类型
    queue.put("hello")  #放入第一个值
    queue.put(1)         #放入第二个值
    queue.put([1,2,3])   #放入第三个值
    #queue.put("a")     #放入第四个值
    #queue.put_nowait("a") #放入五个值
    #打印队列对象
    print(queue)
    
    #获取第一个值
    value1=queue.get()
    print(value1)
    
    #获取第二个值
    value2=queue.get()
    print(value2)
    
    #获取第三个值
    value3=queue.get()
    print(value3)
    
    #获取第四个值
    #value4=queue.get()
    #print(value4)
    
    #value5=queue.get_nowait()
    #print(value5)
    
    

    结果:
    在这里插入图片描述
    队列的长度为三刚好通过put()放入了三个数据属于已满状态,但是有通过get()把三个值取出了此时队列为空。我们加入多添加一个值会出现什么情况呢?
    在这里插入图片描述
    队列已满再添加队列就进入了阻塞状态,默认等待队列先取出放入的新值,在已经满的队列中用queue.put_nowait(“a”)添加会发生什么呢?
    在这里插入图片描述
    我们看到用queue.put_nowait(“a”)添加不在等待直接报错,如果我们把取空的队列再用get()取有会发生什么呢?
    在这里插入图片描述
    这时执行完前面的代码,它会默认等待这放入新值让它取。同样在空队列中使用queue.get_nowait()不会等待放入新值,直接报错。

    消息队列常见的判断

    首先我们创建一个队列

    import multiprocessing
    #创建一个长度为3的队列
    queue=multiprocessing.Queue(3)
    queue.put(1)
    queue.put(2)
    queue.put(3)
    #取值
    queue.get()
    # 1.判断是否已满
    a=queue.full() #返回True为满  False未满
    print("a--->",a)
    #2.取出队列中消息的个数
    print("消息的个数:",queue.qsize())
    # 3.判断是否已经为空
    b=queue.empty()
    print("b--->",b)
    

    结果:
    在这里插入图片描述

    进程间数据共享

    队列到底在进程间是如何进行共享数据,接下我们先用一个图表示一下
    在这里插入图片描述
    两个线程一个在数据放入端通过put()写入数据,一个在读取端通过get()读取数据。

    展开全文
  • 一、线程 1、什么是线程  线程操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的...(1)创建线程的两种方式 直接调用(常用) #!/usr/bin/env python # -*- coding:utf-8 -*- import ...

    一、线程

    1、什么是线程

      线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

    一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

    2、基本使用

    (1)创建线程的两种方式

    直接调用(常用)

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    def f1(arg):   # 定义每个线程要执行的函数
        time.sleep(0.1)
        print(arg,threading.current_thread())    # threading.current_thread()详细的线程信息
    
    for i in range(10):    # 创建10个线程并发执行函数
        t = threading.Thread(target=f1,args=('python',))   # args是函数的参数,元组最后一个必须要逗号,
        t.start()   # 启动线程
    
    print(t.getName())  # 可以获取主线程的名字
    

    继承调用

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    class MyThread(threading.Thread):   # 继承threading.Thread类
        def __init__(self,func,args):
            self.func = func
            self.args = args
            super(MyThread,self).__init__()  # 执行父类的构造方法
    
        def run(self):   # run()方法,是cpu调度线程会使用的方法,必须是run()方法
            self.func(self.args)
    
    def f2(arg):
        time.sleep(0.1)
        print(arg,threading.current_thread())
    
    for i in range(10):   # 创建10个线程
        obj = MyThread(f2,123)
        obj.start()
    

    (2)更多方法  

    自己还可以为线程自定义名字,通过 t = threading.Thread(target=f1, args=(i,), name='mythread{}'.format(i)) 中的name参数,除此之外,Thread还有一下一些方法

    t.join(n)       表示主线程等待子线程多少时间,n表示主线程等待子线程的超时时间,如果在n时间内子线程未完成,主线程不在等待,执行后面的代码
    t.run()         线程被cpu调度后自动执行线程对象的run方法(一般我们无需设置,除非自己定义类调用)
    t.start()       线程准备就绪,等待CPU调度
    t.getName()     获取线程的名称
    t.setName()     设置线程的名称 
    t.name          获取或设置线程的名称
    t.is_alive()    判断线程是否为激活状态
    t.isAlive()     判断线程是否为激活状态
    t.isDaemon()    判断是否为守护线程
    t.setDaemon     设置True或False(默认)
                       True表示主线程不等待子线程全部完成就执行后面的代码
                       False默认值,标识主线程等待子线程全部执行完后继续执行后面的代码
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    def f1(arg):
        time.sleep(5)
        print(arg)
    
    t = threading.Thread(target=f1,args=('python',))
    t.setDaemon(True) # 默认是False,设置为true表示主线程不等子线程
    t.start()  
    t.join(2)  # 表示主线程到此,等待子线程执行完毕,2表示主线程最多等待2秒
    
    print('end') # 默认主线程在等待子线程结束
    print('end')
    print('end')
    

    3、线程锁(Lock、RLock)  

      由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。这里使用Rlock,而不使用Lock,因为Lock如果多次获取锁的时候会出错,而RLock允许在同一线程中被多次acquire,但是需要用n次的release才能真正释放所占用的琐,一个线程获取了锁在释放之前,其他线程只有等待。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    NUM = 10
    
    def func(l):
        global NUM
        # 上锁
        l.acquire()
        NUM -=1
        time.sleep(0.1)
        print(NUM,threading.current_thread())
        # 开锁
        l.release()
    
    # lock = threading.Lock()
    lock = threading.RLock()  # 递归锁
    
    for j in range(10):
        t = threading.Thread(target=func,args=(lock,))
        t.start()
    

    4、信号量(Semaphore)

      互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    import time
    
    NUM = 30
    
    def func(i,l):
        global NUM
        # 上锁
        l.acquire()
        NUM -=1
        time.sleep(1)
        print(NUM,i,threading.current_thread())
        # 开锁
        l.release()
    
    lock = threading.BoundedSemaphore(5)  # 设置信号量5,表示同时5个线程同时执行
    
    for i in range(30):
        t = threading.Thread(target=func,args=(i,lock,))
        t.start()
    

    5、事件(event)

      python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

    事件处理的机制:全局定义了一个"Flag",如果"Flag"值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果"Flag"值为True,那么event.wait 方法时便不再阻塞。

    • clear:将"Flag"设置为False
    • set:  将"Flag"设置为True
    • wait: 检测当前"Flag",如果"Flag"值为 False,那么当线程执行 event.wait 方法时就会阻塞,如果"Flag"值为True,那么event.wait 方法时便不再阻塞。

    下面是一个红绿灯的例子,主线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    
    def func(i,e):
        print(i)
        e.wait()  # 检测是什么灯,如果是True红灯,停;绿灯False行,默认是红灯
        print(i+100)
    
    
    event = threading.Event()
    
    for i in range(10):
        t = threading.Thread(target=func,args=(i,event,))
        t.start()
    
    event.clear()  # 主动设置成红灯,默认是红灯,此句可以不写
    inp = input('>>>')
    if inp == '1':
        event.set()  # 设置成绿灯,就会执行func()函数中print(i+100)语句
    

    6、条件(Condition)

    使得线程等待,只有满足某条件时,才释放n个线程

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import threading
    
    def func(i,con):
        print(i)
        con.acquire()  # 固定写法acquire,wait
        con.wait()
        print(i+100)
        con.release()
    
    c = threading.Condition()  # 设置条件
    
    for i in range(10):
        t = threading.Thread(target=func,args=(i,c,))
        t.start()
    
    
    while True:
        inp = input('>>>')
        if inp == 'q':
            break
        c.acquire() # 这里是固定写法,acquire,notify,release
        c.notify(int(inp))
        c.release()
    

    第二种

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import threading
    
    def condition():
        ret = False
        r = input('>>>')
        if r == 'true':
            ret = True
        else:
            ret = False
        return ret
    
    def func(i,con):
        print(i)
        con.acquire()
        con.wait_for(condition)  # 和上一个例子的差别在这里
        print(i+100)
        con.release()
    
    c = threading.Condition()
    for i in range(10):
        t = threading.Thread(target=func,args=(i,c,))
        t.start()
    

    6、Timer

    定时器,指定n秒后执行某操作

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from threading import Timer
    
    def hello():
        print("hello python")
    
    t = Timer(1,hello)
    t.start() 

    7、线程池,点击这里  

    二、进程  

      线程的上一级就是进程,进程可包含很多线程,进程和线程的区别是进程间的数据不共享,多进程也可以用来处理多任务,不过多进程很消耗资源,计算型的任务最好交给多进程来处理,IO密集型最好交给多线程来处理,此外进程的数量应该和cpu的核心数保持一致。  

    1、线程与进程的区别

    1、线程共享创建它的进程的地址空间,进程有自己的地址空间。
    2、线程是直接可以访问线程之间的数据;进程需要复制父进程的数据才能访问。
    3、线程可以直接与其他线程的通信过程,进程必须使用进程间通信和同胞交流过程。
    4、新创建一个线程很容易;新创建一个进程需要复制父进程。
    5、主线程可以控制相当大的线程在同一进程中;进程只能控制子进程。
    6、主线程变更(取消、优先级变化等)可能会影响进程的其他线程的行为;父进程的变化不会影响子进程。

    2、基本使用

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from multiprocessing import Process
    
    def foo(i):
        print('say hi',i)
    
    for i in range(10):
        p = Process(target=foo,args=(i,))
        #p.daemon = True  # 和线程t.setdaemon是一样的
        p.start()
        #p.join()
    

    注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。其他使用方法和线程threading.Thread是一样的  

    3、进程数据共享

    进程各自持有一份数据,默认无法共享数据;queues,Array,Manager.dict,pipe这些方法都能实现数据共享

    (1)特殊队列queues()

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Process
    from multiprocessing import queues
    import multiprocessing
    
    def foo(i,arg):
        arg.put(i)
        print('say hi',i,arg.qsize())
    
    li = queues.Queue(20,ctx=multiprocessing)
    
    for i in range(10):
        p = Process(target=foo,args=(i,li,))
        p.start()
    

    (2)数组Array()

    数组和列表很像,但是数组中的元素在内存中的地址是一段连续的空间地址,而列表中的元素则不是一段连续的的地址,是通过链表的形式找到下一个元素

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Process
    from multiprocessing import Array
    
    def foo(i,arg):
        arg[i] = i+100
        for item in arg:
            print(item)
    
    li = Array('i',10)  # 指定数组时需要指定类型
    for i in range(10):
        p = Process(target=foo,args=(i,li,))
        p.start()
    
        'c': ctypes.c_char,  'u': ctypes.c_wchar,
        'b': ctypes.c_byte,  'B': ctypes.c_ubyte,
        'h': ctypes.c_short, 'H': ctypes.c_ushort,
        'i': ctypes.c_int,   'I': ctypes.c_uint,
        'l': ctypes.c_long,  'L': ctypes.c_ulong,
        'f': ctypes.c_float, 'd': ctypes.c_double
    类型对应表

    (3)Manager.dict()

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Process
    from multiprocessing import Manager
    
    def foo(i,arg):
        arg[i] = i +100
        print(arg.values())
    
    obj = Manager()
    li = obj.dict()
    for i in range(10):
        p = Process(target=foo,args=(i,li,))
        p.start()
        p.join()
    

    (4)pipe()

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Process, Pipe
    
    def f(conn):
        conn.send([42, None, 'hello'])
        conn.close()
    
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # 父进程可以收到子进程的共享信息prints "[42, None, 'hello']" 
    p.join()

    4、进程池

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

    进程池中有两个方法:

    • apply
    • apply_async
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    from multiprocessing import Pool
    import time
    
    def f1(arg):
        time.sleep(1)
        print(arg)
    
    pool = Pool(5)
    
    for i in range(30):  # 定义30个任务
        #pool.apply(func=f1,args=(i,))  # 所有进程串行执行没有多大意义
        pool.apply_async(func=f1,args=(i,)) # 异步并行执行
    
    pool.close() #等待所有的任务执行完毕
    #time.sleep(1)
    #pool.terminate()  # 立即终止子进程的任务,主进程继续执行
    pool.join() # 执行pool.join时必须先执行pool.close或者pool.terminate
                # 进程池中进程执行完毕后在关闭,如果注释,那么程序直接关闭close,terminate也无效
    print('end')
    

    三、协程

      线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

    协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

    协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;由greenlet,gevent实现,gevent是调用greenlet进行封装;需要安装pip install greenlet;pip install gevent;

    greenlet  

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
     
    from greenlet import greenlet
     
     
    def test1():
        print 12
        gr2.switch()
        print 34
        gr2.switch()
     
     
    def test2():
        print 56
        gr1.switch()
        print 78
     
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    gr1.switch()
    

    gevent

    import gevent
     
    def foo():
        print('Running in foo')
        gevent.sleep(0)
        print('Explicit context switch to foo again')
     
    def bar():
        print('Explicit context to bar')
        gevent.sleep(0)
        print('Implicit context switch back to bar')
     
    gevent.joinall([
        gevent.spawn(foo),
        gevent.spawn(bar),
    ])
    

    遇到IO操作自动切换:此操作在python2.x中执行的,urllib2不支持python3.x

    from gevent import monkey; monkey.patch_all()
    import gevent
    import urllib2
    
    def f(url):
        print('GET: %s' % url)
        resp = urllib2.urlopen(url)
        data = resp.read()
        print('%d bytes received from %s.' % (len(data), url))
    
    gevent.joinall([
            gevent.spawn(f, 'https://www.python.org/'),
            gevent.spawn(f, 'https://www.yahoo.com/'),
            gevent.spawn(f, 'https://github.com/'),
    ])
    

    四、queue队列  

    queue有哪些队列? 

    • queue.Queue(maxsize) 先进先出队列
    • queue.LifoQueue(maxsize) 后进先出
    • queue.PriorityQueue(maxsize) 优先级队列
    • queue.deque(maxsize) 双向队列

    先进先出

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import queue
    
    q = queue.Queue(5)  # 默认maxsize=0无限接收,最大支持的个数
    print(q.empty())    # 查看队列是否为空
    q.put(11)           # put防数据,是否阻塞默认是阻塞block=True,timeout超时时间
    q.put(22)
    q.put(33,block=False,timeout=2)
    print(q.full())     # 查看队列是否已经放满
    print(q.qsize())    # 队列中多少元素
    print(q.maxsize)    # 队列最大支持的个数
    print(q.get(block=False,timeout=2))  # get取数据,是否阻塞默认是阻塞block=True,timeout超时时间
    print("*" * 10)
    
    print(q.get())
    q.task_done()       # join配合task_done,队列中有任务就会阻塞进程,当队列中的任务执行完毕之后,不在阻塞
    print(q.get())
    q.task_done()
    q.join()            # 队列中还有元素的话,程序就不会结束程序,只有元素被取完配合task_done执行,程序才会结束
    

    后进先出

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import queue
    
    q = queue.LifoQueue()
    q.put(123)
    q.put(456)
    print(q.get())
    

    优先级队列 

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import queue
    
    q = queue.PriorityQueue()
    q.put((1,'python1'))
    q.put((5,'python'))
    q.put((3,'python3'))
    print(q.get())
    

    双向队列  

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import queue
    
    q = queue.deque()
    q.append(123)
    q.append(333)
    q.appendleft(456)
    print(q.pop())
    print(q.popleft())

    更多请查看官方文档

    生产者消费者模型

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import queue
    import threading
    import time
    q = queue.Queue()
    
    def productor(arg):
        while True:
            q.put(str(arg))
            print('%s 号窗口有票' %str(arg))
            time.sleep(1)
    
    for i in range(3):
        t = threading.Thread(target=productor,args=(i,))
        t.start()
    
    
    def consumer(arg):
        while True:
            print('第 %s 人取 %s 号窗口票' %(str(arg),q.get()))
            time.sleep(1)
    
    for j in range(300):
        t = threading.Thread(target=consumer,args=(j,))
        t.start()
    

      

    转载于:https://www.cnblogs.com/xiaozhiqi/p/5796967.html

    展开全文
  • 目录进程补充进程通信前言Queue队列的基本使用通过Queue队列实现进程间通信(IPC机制)生产者消费者模型以做包子买包子为例实现当包子卖完了停止消费行为方式一方式二线程什么是线程为什么要有线程开进程开线程开启...

    进程补充

    进程通信前言

    要想实现进程间通信,可以用管道或者队列

    队列比管道更好用(队列自带管道和锁)

    队列特点:先进先出

    堆栈特点:先进后出

    我们采用队列来实现进程间数据通信,下面先介绍一下队列

    Queue队列的基本使用

    基本方法:q.put(元素) q.get() q.get_nowait() q.full() q.empty()

    from multiprocessing import Process, Queue
    
    q = Queue(5)  # 实例化出一个对象
    # --------------------------------------
    # q.put(元素) 往队列里放东西
    #   如果队列满了还往里面放,就会等在这里
    # --------------------------------------
    # q.put(1)
    # q.put(2)
    # q.put(3)
    # --------------------------------------
    # # q.full() 判断队列有没有满
    # --------------------------------------
    # print(q.full())  # q.full 判断队列有没有满
    # # False
    # q.put(4)
    # q.put(5)
    # # q.put(6)  # 如果队列满了还往里面放,就会等在这里
    # print(q.full())
    # # True
    
    for i in range(5):
        q.put(i)
    print(q.full())
    # True
    # --------------------------------------
    # q.get() 从队列头取一个值
    #   如果队列空了,就会等在这里,等数据过来
    # --------------------------------------
    print(q.get())
    print(q.full())
    # 0
    # False
    print(q.get())
    print(q.get())
    # print(q.get())
    # --------------------------------------
    # q.get_nowait() 从队列头取一个值
    #   在队列有数据的情况下,与get取值一样
    #   当队列没有值的情况下,取值直接报错
    # --------------------------------------
    print(q.get_nowait())  # 在队列有数据的情况下,与get取值一样,当队列没有值的情况下,取值直接报错
    # --------------------------------------
    # q.empty() 判断队列是否为空
    #   在并发的情况下,这个方法不准确
    # --------------------------------------
    print(q.empty())  # 判断队列是否为空,需要注意的是在并发的情况下,这个方法不准确
    print(q.get())
    # 1
    # 2
    # 3
    # False
    # 4
    # print(q.get())  # 如果队列空了,就会等在这里,等数据过来
    print(q.empty())
    # True
    # print(q.get_nowait())
    # 直接报错 queue.Empty

    通过Queue队列实现进程间通信(IPC机制)

    数据的互通,可实现主进程与子进程之间的互通,子进程与子进程之间的互通
    数据只有一份,取完就没了,无法重复获取同一份数据

    from multiprocessing import Queue, Process
    
    
    def producer(q):
        q.put('hello baby.')
    
    
    def consumer(q):
        print(q.get())
    
    
    if __name__ == '__main__':
        q = Queue()  # 生成一个队列对象
        p1 = Process(target=producer, args=(q,))
        c1 = Process(target=consumer, args=(q,))
        p1.start()
        c1.start()  # 子进程获取到了另一个子进程的数据
        # hello baby.
        # print(q.get())  # 主进程获取到了子进程的数据
        # hello baby.

    生产者消费者模型

    生产者:生产/制造数据的

    消费者:消费/处理数据的

    例子:做包子的,卖包子的
    	1.做的包子远比买包子的多
    	2.做的包子远比买包子的少
    	--> 供需不平衡

    用处:解决供需不平衡的问题

    以做包子买包子为例实现当包子卖完了停止消费行为

    方式一

    from multiprocessing import Process, Queue
    import time
    import random
    
    
    def producer(name, food, q: Queue):
        for i in range(10):
            data = f'{name} 生产了 {food}{i}'
            time.sleep(random.random())
            q.put(data)
            print(data)
    
    
    def consumer(name, q):
        while True:
            res = q.get()
            if not res:  # 已经把生产者做的东西全部吃完了,那么本消费者也结束食用
                break
            data = res.split(' ')[2]
            data = f'{name} 吃了 {data}'
            print(data)
            time.sleep(random.random())
    
    
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=producer, args=('大厨egon', '馒头', q))
        p2 = Process(target=producer, args=('跟班tank', '生蚝', q))
        c = Process(target=consumer, args=('jason', q))
        c2 = Process(target=consumer, args=('吃货kevin', q))
        p.start()
        p2.start()
        c.start()
        c2.start()
        # 不知道什么时候生产者什么时候生成完
        p.join()
        p2.join()
        q.put(None)  # 通过 None来标志生产者已生产完成
        q.put(None)
        # 可以实现,但是不好

    方式二

    改用JoinableQueue模块的队列守护进程来实现

    from multiprocessing import Process, JoinableQueue
    import time
    import random
    
    
    def producer(name, food, q: JoinableQueue):
        for i in range(10):
            data = f'{name} 生产了 {food}{i}'
            time.sleep(random.random())
            q.put(data)
            print(data)
    
    
    def consumer(name, q):
        while True:
            res = q.get()
            if not res:
                break
            data = res.split(' ')[2]
            data = f'{name} 吃了 {data}'
            print(data)
            time.sleep(random.random())
            q.task_done()  # 告诉队列,你已经从队列中取出了一个数据,并且处理完毕了
    
    
    if __name__ == '__main__':
        q = JoinableQueue()
        p = Process(target=producer, args=('大厨egon', '馒头', q))
        p2 = Process(target=producer, args=('跟班tank', '生蚝', q))
        c = Process(target=consumer, args=('jason', q))
        c2 = Process(target=consumer, args=('吃货kevin', q))
        p.start()
        p2.start()
        c.daemon = True  # 配合join,结束程序消费者也结束(注意join是主进程的最后一句代码)
        c.start()
        c2.daemon = True
        c2.start()
        # 不知道什么时候生产者什么时候生成完
        p.join()
        p2.join()
    
        q.join()  # 等待队列中数据全部取出,执行完了这句话,也就意味着队列中没有数据了(消费者那里还是会卡住,get不到东西等待)
        # 配合上 守护进程 来实现....

    线程

    什么是线程

    进程和线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物

    进程:资源单位(一块独立的内存空间)

    线程:执行单位

    将内存比喻成工厂,那么进程就相当于工厂里的车间,而你的线程就相当于是车间里面的流水线

    CPU其实运行的其实是线程,进程只是资源单位

    线程执行时需要的资源单位都跟进程要

    ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源

    每个进程都会自带一个线程

    线程没有主次之分,只不过我们默认就把主进程自带的那个线程叫做主线程

    为什么要有线程

    开进程

    • 申请内存空间 ---> 耗资源
    • “拷贝代码” ---> 耗资源

    开线程

    • 一个进程内可以起多个线程,并且线程与线程之间数据是共享的

    ps:开启线程的开销要远远小于开启进程的开销(可能刚执行完创建线程的代码线程就创建好了)

    开启线程的两种方式

    方式一

    from threading import Thread
    import time
    
    
    def task(name):
        print(f"{name} is running")
        time.sleep(3)
        print(f"{name} is over")
    
    
    t = Thread(target=task, args=('egon', ))  # 开线程不需要在 __main__ 代码块内,但是习惯性的还是写在 __main__ 内
    t.start()  # 告诉操作系统开启一个线程
    # 线程的开销远远小于进程,小到以至于可以代码执行完,线程就已经开启了
    print("主")  # 线程没有主次之分,都在同一个进程的名称空间里,只是人为把进程自带的线程叫做主线程
    # egon is running
    # 主线程  # 进程的时候这个主线程可能会是最先打印的
    # egon is over

    方式二

    from threading import Thread
    import time
    
    
    class MyThread(Thread):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print(f"{self.name} is running")
            time.sleep(1)
            print(f"{self.name} is over")
    
    
    if __name__ == '__main__':
        t = MyThread('jason')
        t.start()  # 开启线程的速度非常快,几乎代码执行完线程就已经开启
        print("主")
    
    # jason is running
    # 主
    # jason is over

    线程之间数据共享

    from threading import Thread
    
    money = 666
    
    
    def task():
        global money
        money = 999
    
    
    t = Thread(target=task)
    t.start()
    t.join()  # 确保是线程运行结束后
    print(money)
    # 999  # 主线程与子线程之间数据是通用的

    线程间想要实现数据通信,不需要借助于队列(线程间支持数据通信)

    线程对象的其他属性和方法

    import time
    from threading import Thread, active_count, current_thread
    import os
    
    
    def task(name):
        print(f"{name} is running {os.getpid()}")
        # # ------------------------------------------------
        # # current_thread().name current_thread().getname() 当前线程名
        # #   记得导入模块
        # # ------------------------------------------------
        # print(f"current_thread().name:{current_thread().name}")
        # current_thread().name:Thread-1
        time.sleep(1)
        print(f"{name} is over")
    
    
    # t = Thread(target=task, args=('jason', ))
    # t.start()
    # # ------------------------------------------------
    # # os.getpid() os.getppid() 获取进程号 父进程号
    # #   多个线程属于同一进程
    # # ------------------------------------------------
    # print(f"pid {os.getpid()}")
    # # jason is running 5572
    # # pid 5572
    # # jason is over
    
    
    t = Thread(target=task, args=('jason', ))
    t.start()
    # ------------------------------------------------
    # active_count()  统计当前存活的线程数
    #   记得导入模块
    # ------------------------------------------------
    print(active_count())
    print(f"pid {os.getpid()}")
    # jason is running 5728
    # 2
    # pid 5728
    print(f"主 current_thread().name:{current_thread().name}")
    # 主 current_thread().name:MainThread
    
    t.join()  # 主线程等待子线程运行结束
    # jason is over
    print("主 active_count", active_count())  # 可能会有问题,多线程是异步,可能join的线程结束了,其他线程也正好结束了(多个线程时)
    # 主 active_count 1
    # Thread.join(t)  # 可以考虑用类调用对象方法,传入对象来在循环里对线程对象进行操作

    守护线程

    主线程要等待所有非守护线程结束后才会结束(不是主线程的代码执行完了就立马结束了)

    主线程结束后,守护(子)线程也会立即结束

    主线程运行结束之后为什么需要等待子线程结束才能结束呢?

    主线程的结束也就意味着进程的结束
    主线程必须等待其他非守护线程的结束才能结束
    因为子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了,资源也就销毁了

    # from threading import Thread, current_thread
    # import time
    #
    #
    # def task(i):
    #     print(f"{current_thread().name}")
    #     time.sleep(i)
    #     print("GG")
    #
    #
    # for i in range(3):
    #     t = Thread(target=task, args=(i, ))
    #     t.start()
    #
    #
    # print("主")
    # # 循环的时候就已经打印了部分数据了(异步)
    # # Thread-1
    # # GG
    # # Thread-2
    # # Thread-3
    # # 主
    # # GG
    # # GG
    
    # 主线程运行结束之后为什么需要等待子线程结束才能结束呢?
    '''
    主线程的结束也就意味着进程的结束
        主线程必须等待其他非守护线程的结束才能结束
    因为子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了,资源也就销毁了
    '''
    from threading import Thread, current_thread
    import time
    
    
    def task(i):
        print(f"{current_thread().name}")
        time.sleep(i)
        print("GG")
    
    
    for i in range(3):
        t = Thread(target=task, args=(i,))
        t.daemon = True
        t.start()
    
    print("主")
    # Thread-1
    # GG
    # Thread-2
    # Thread-3
    # 主

    测试

    下面程序的执行结果是什么?

    from threading import Thread
    import time
    
    
    def foo():
        print(123)
        time.sleep(1)
        print("end123")
    
    
    def bar():
        print(456)
        time.sleep(3)
        print("end456")
    
    
    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    
    t1.daemon = True
    t1.start()
    t2.start()
    print("main-------")
    
    
    # 123
    # 456
    # main-------
    # end123
    # end456

    线程互斥锁

    从线程间通信那里的案例可以看出,线程间数据是相通的,那么多个线程对同一份数据进行操作会产生问题

    下面同样模拟一个网络延迟来对数据进行操作(确保所有线程都执行完的操作可以记一下)

    不加锁遇到延迟的情况

    # 模拟网络延迟的现象
    #   多个线程操作同一个数据,也会造成数据不安全
    import time
    from threading import Thread
    
    n = 10
    
    
    def task():
        global n
        tmp = n
        time.sleep(1)
        n = tmp - 1
    
    
    # -------------------------------
    t_list = []
    for i in range(10):
        t = Thread(target=task)
        t.start()
        t_list.append(t)
    
    # 确保其他线程都执行完了之后再打印
    for t in t_list:
        t.join()
    # -------------------------------
    
    print(n)
    # 9

    加锁后遇到延迟

    # 加锁解决问题
    import time
    from threading import Thread, Lock
    
    n = 10
    
    
    def task(mutex):
        mutex.acquire()  # 抢锁
        global n
        tmp = n
        time.sleep(1)
        n = tmp - 1
        mutex.release()  # 释放锁
    
    
    t_list = []
    mutex = Lock()
    for i in range(10):
        t = Thread(target=task, args=(mutex, ))
        t.start()
        t_list.append(t)
    
    # 确保其他线程都执行完了之后再打印
    for t in t_list:
        t.join()
    print(n)
    # 0  # 等10s多点 后打印出结果,数据未受延迟影响,保证了数据安全

    为什么用互斥锁不用 线程/进程对象.join()

    虽然互斥锁也是将并发改成串行,牺牲效率来保证数据安全,这一点线程对象.join()也可以实现将并发改成串行,同样保证数据安全,但线程对象.join()是将每一个线程的运行都变成串行的,对比互斥锁的只将数据操作部分编程串行消耗的时间要多得多,若果线程耗时长,执行效率就会低的可怕

    # # 不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全
    # from threading import current_thread, Thread, Lock
    # import os
    # import time
    #
    #
    # def task():
    #     # 未加锁的代码并发运行
    #     time.sleep(3)
    #     print('%s start to run' % current_thread().getName())
    #     global n
    #     # 加锁的代码串行运行
    #     lock.acquire()
    #     temp = n
    #     time.sleep(0.5)
    #     n = temp - 1
    #     lock.release()
    #
    #
    # if __name__ == '__main__':
    #     n = 100
    #     lock = Lock()
    #     threads = []
    #     start_time = time.time()
    #     for i in range(100):
    #         t = Thread(target=task)
    #         threads.append(t)
    #         t.start()
    #     for t in threads:
    #         t.join()
    #     stop_time = time.time()
    #     print('主:%s n:%s' % (stop_time - start_time, n))
    #
    # '''
    # Thread-3 start to run
    # Thread-1 start to run
    # ......
    # Thread-100 start to run
    # Thread-96 start to run
    # 主:53.06105661392212 n:0
    # '''
    
    # 利用 join 保证数据安全
    from threading import current_thread, Thread, Lock
    import os
    import time
    
    
    def task():
        time.sleep(3)
        print('%s start to run' % current_thread().getName())
        global n
        temp = n
        time.sleep(0.5)
        n = temp - 1
    
    
    if __name__ == '__main__':
        n = 100
        lock = Lock()
        start_time = time.time()
        for i in range(100):
            t = Thread(target=task)
            t.start()
            t.join()
        stop_time = time.time()
        print('主:%s n:%s' % (stop_time - start_time, n))
    
    '''
    Thread-1 start to run
    Thread-2 start to run
    ......
    Thread-100 start to run
    主:350.1616487503052 n:0 # 耗时是多么的恐怖
    '''

    线程和进程的用户大同小异,可以对比着来记

    后续可以画图或表格用对比的方式来整理一下,方便记忆~

    展开全文
  • 前面博文介绍了Linux间进程通信方式实际上效率不是很高,假如在进程中进行快速、大量数据传输时候,使用管道、消息队列这样通信方式就不合适了,这里介绍到另外一高效的进程间通信方式:共享内存。...
  • 二叉堆之优先队列

    2014-12-22 21:41:54
    一、优先队列不同于普通队列采用先进先出的队列元素存取方式。插入队列元素时按照一定的规则插入,每次都队列中优先级最高的元素。在操作系统中,调度程序必须决定在... 优先队列具备的最基本的两种操作,插入和
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 优先队列之二叉堆

    2010-10-30 16:18:00
    在操作系统中,调度程序必须决定在什么时候运行哪个进程。... 优先队列具备的最基本的两种操作,插入和删除最小者。插入操作相当于入列,而删除操作相当于出队。只是这里有一些地方不同的,不像之前出队...
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 个或多个进程之间交互数据过程,因为进程之间相互独立,为了能够让多个进程协同工作必须交换数据 进程间通信分类 ​ 简单的进程间通信:信号、文件、环境变量、命令行参数 ​ 传统的进程间通信:...
  • 什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • 环境编程07

    2020-09-14 11:20:00
    什么是进程间通信:个或多个进程之间交互数据过程,因为进程之间相互独立,为了协同工作必须交互数据。 进程间通信分类: 简单的进程间通信:信号、文件、环境变量、命令行参数。 传统的进程间通信:...
  • Java线程池及相关概念

    2020-09-26 22:31:54
    线程调度CPU最小单元(进程资源分配的最小单元),也叫轻量级进程,可以理解为进程的执行流。创建了一个进程就会创建一个线程(主线程),也就是一个进程至少包含一个线程。 二.线程主要有个作用 1.提高多核cpu...
  • 一、RabbitMQ 简介

    2020-05-12 17:27:08
    一、什么是消息中间件 1.1 简介 消息(Message)指在应用间传送数据。消息可以非常简单,比如只包含文本字符串、 JSON等,也可以很复杂,比如内嵌对象。 消息队列中间件...它一般有两种传递...
  • RocketMQ是什么 是由阿里捐赠给Apache一款分布式、队列模型开源消息中间件,经历了双十一洗礼。 RocketMQ发展史 RocketMQ特性 原生分布式 两种消息拉取 严格消息顺序 特有分布式协调器 亿级消息堆积 ...
  • 答:高响应比优先调度算法的基本思想把CPU分配给就绪队列中响应比最高的进程。既考虑作业执行时间也考虑作业等待时间,综合了先来先服务和最短作业优先两种算法特点。该算法中响应比指作业等待时间与运行...
  • 4.1.0 JAVA中种基本数据类型是什么,各自占用多少字节。 4.1.1 String类能被继承吗,为什么。 4.1.2 String,Stringbuffer,StringBuilder区别。 4.1.3 ArrayList和LinkedList有什么区别。 4.1.4 讲讲类...
  • 三个基本状态等待、执行和就绪,在一定的条件下,进程的状态将发生转换。 (2)进程调度算法 主要有先来先服务(FCFS)、时间片轮转法、多级反馈轮转法、优先数法。 (3)进程控制块(PCB)进程...
  • C++程序员面试宝典

    热门讨论 2013-04-01 13:36:19
    面试题37 C++中有哪几种基本数据类型 38 面试题38 整型有哪几种形式?各种形式有什么区别 39 面试题39 C++中有哪些常量 40 面试题40 常量与变量有哪些区别 42 4.2 操作符 42 面试题41 操作符有哪些分类 43 面试题42 ...
  • 事务处理原理 第2版

    热门讨论 2012-12-30 10:49:38
    我们通过很多产品范例来演示说明如何应用这些原理以及这些想法什么情况下产生,但不可能详细地叙述每一产品。本书介绍实用且在产品中使用到技术,并适当介绍实践当中不常用一些好想法。  阅读本书...
  • 2.进程调度方式通常有(抢占 )和(非抢占)两种方式。 3.每个索引文件都必须有一张( 索引结点 )表,其中地址登记项用来指出文件在外存上位置信息。 4.在一请求分页系统中,假如一个作业页面走向为:4...
  • 命令组件: PBS支持与POSIX1003.2d相一致命令行和图形接口两种命令方式。这些命令用于提交、监视、修改和删除作业。命令可以被安装在任何PBS支持系统类型上,并且不需要在本地安装任何其它PBS组件。共有三种...
  • 8.4.4 当个表达式相等时候返回NULL值,否则返回第一个表达式 232 8.5 日期函数 233 8.5.1 返回当前日期和时间 233 8.5.2 在时区间进行转换 234 8.5.3 增加或减少日期值 235 8.5.4 找出个日期差 ...
  • 最后讲解了Linux内核中常见同步机制,使读者掌握每处理器变量和RCU这两种 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...
  • 最后讲解了Linux内核中常见同步机制,使读者掌握每处理器变量和RCU这两种 同步机制。 《Linux2.6内核标准教程》适合Linux内核爱好者、Linux驱动开发人员、Linux系统工程师参考使用,也可以作为计算机及相关...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 124
精华内容 49
关键字:

进程的两种基本队列是什么