zoukankan      html  css  js  c++  java
  • 3.进程与线程

    1.进程

    1.1定义

    程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。

    程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。

    在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。

    进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。

    1.2优点

    进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。

    进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

    但是也有缺陷:

    • 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。

    • 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。

    2.线程

    2.1定义

    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,

    只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。


    3.应用

    3.1区别

    进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

    1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.

    2) 线程的划分尺度小于进程,使得多线程程序的并发性高。

    3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

    4) 但是线程不能够独立执行必须依存在应用程序中,由应用程序提供多个线程执行控制。

    3.2 Python里的线程(threading模块) 

    线程调用的方法2种:

    函数调用

    import threading, time
    
    
    def fun(name):  # 定义每个线程要运行的函数
    
        print("%s running on fun" % name)
    
        time.sleep(2)
    
    
    if __name__ == '__main__':  # 要运行的主程序,window下一定要写,作为导入模块时不执行后面的代码
    
        t1 = threading.Thread(target=fun, args=(1,))  # 生成一个线程实例
        t2 = threading.Thread(target=fun, args=(2,))  # 生成另一个线程实例
    
        t1.start()  # 启动线程
        t2.start()  # 启动另一个线程
    
        print(t1.getName())  # 获取线程名
        print(t2.getName())
    View Code

    类调用

    import threading, time
    
    class MyThread(threading.Thread):
        def __init__(self, name):
            threading.Thread.__init__(self)
            self.name = name   
        def fun(self):  # 定义每个线程要运行的函数 
            print("%s running on fun" % self.name)      
            time.sleep(2)
    
    if __name__ == '__main__':
        t1 = MyThread(1)
        t2 = MyThread(2)
        t1.start()
        t2.start()
    View Code

    join与Daemon

    几个事实

    1 python 默认参数创建线程后,不管主线程是否执行完毕,都会等待子线程执行完毕才一起退出,有无join结果一样

    2 如果创建线程,并且设置了daemon为true,即thread.setDaemon(True), 则主线程执行完毕后自动退出,不会等待子线程的执行结果。而且随着主线程退出,子线程也消亡。

    3 join方法的作用是阻塞,等待子线程结束,join方法有一个参数是timeout,即如果主线程等待timeout,子线程还没有结束,则主线程强制结束子线程。

    4 如果线程daemon属性为False, 则join里的timeout参数无效。主线程会一直等待子线程结束。

    import time
    import threading
     
    def run(n):
        print('[%s]------running----
    ' % n)
        time.sleep(2)
        print('--done--')
     
    def main():
        for i in range(5):
            t = threading.Thread(target=run,args=[i,])
            t.start()
            t.join(1)
            print('starting thread', t.getName())
     
     
    m = threading.Thread(target=main,args=[])
    m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务
    m.start()
    m.join(timeout=2)  #主线程等待子线程时间
    print("---main thread done----")
    View Code

    线程锁(互斥锁) 

    多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据。没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期,这种现象称为“线程不安全”。最简单的同步机制是引入互斥锁。互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

    threading模块中定义了Lock类,可以方便的处理锁定:

    #创建锁
    mutex = threading.Lock()
    #锁定
    mutex.acquire([timeout])
    #释放
    mutex.release()

    其中,锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。

    import threading
    import time
    
    class MyThread(threading.Thread):
        def run(self):
            global num 
            time.sleep(1)
    
            if mutex.acquire(1):  
                num = num+1
                msg = self.name+' set num to '+str(num)
                print msg
                mutex.release()
    num = 0
    mutex = threading.Lock()
    def test():
        for i in range(5):
            t = MyThread()
            t.start()
    if __name__ == '__main__':
        test()
    View Code

     semaphore(信号量)

    semaphore是一个内置的计数器

    每当调用acquire()时,内置计数器-1
    每当调用release()时,内置计数器+1

    计数器不能小于0,当计数器为0时,acquire()将阻塞线程直到其他线程调用release()

    import time
    import threading
    
    s1=threading.Semaphore(5)   #添加一个计数器
    
    def foo():
        s1.acquire()    #计数器获得锁
        time.sleep(2)   #程序休眠2秒
        print("ok",time.ctime())
        s1.release()    #计数器释放锁
    
    
    for i in range(20):
        t1=threading.Thread(target=foo,args=()) #创建线程
        t1.start()  #启动线程 
    View Code

    Event方法

    通过Event来实现两个或多个线程间的交互

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

    • clear:将“Flag”设置为False
    • set:将“Flag”设置为True

    用 threading.Event 实现线程间通信
    使用threading.Event可以使一个线程等待其他线程的通知,我们把这个Event传递到线程对象中,
    Event默认内置了一个标志,初始值为False。
    一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时,
    该Event会通知所有等待状态的线程恢复运行。

    import threading,time
    import random
    def light():
        if not event.isSet():
            event.set() #wait就不阻塞 #绿灯状态
        count = 0
        while True:
            if count < 10:
                print('33[42;1m--green light on---33[0m')
            elif count <13:
                print('33[43;1m--yellow light on---33[0m')
            elif count <20:
                if event.isSet():
                    event.clear()
                print('33[41;1m--red light on---33[0m')
            else:
                count = 0
                event.set() #打开绿灯
            time.sleep(1)
            count +=1
    def car(n):
        while 1:
            time.sleep(random.randrange(10))
            if  event.isSet(): #绿灯
                print("car [%s] is running.." % n)
            else:
                print("car [%s] is waiting for the red light.." %n)
    if __name__ == '__main__':
        event = threading.Event()
        Light = threading.Thread(target=light)
        Light.start()
        for i in range(3):
            t = threading.Thread(target=car,args=(i,))
            t.start()
    View Code

    queue模块

    queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递。

    queue.qsize()查队列大小

    基本FIFO队列(queue.Queue(maxsize=0

    Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。

    一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。

    import Queue
    
    q = queue.Queue()
    
    for i in range(5):
        q.put(i)
    
    while not q.empty():
        print q.get()

    LIFO队列(queue.LifoQueue(maxsize=0))

     LIFO即Last in First Out,后进先出。与栈的类似,使用也很简单,maxsize用法同上

    优先级队列(queue.PriorityQueue(maxsize=0) )

  • 相关阅读:
    python字符串以单词形式反转
    python if 语句的练习
    Python对元祖的操作
    Python对列表的操作
    Python对字符串的操作
    导出EXCEL【Web方式HTML通过拼接html中table】
    链接点击跳动问题
    maven报uri is not registered错误
    maven配置
    三级分类的sql语句
  • 原文地址:https://www.cnblogs.com/jack-liu6/p/7859286.html
Copyright © 2011-2022 走看看