zoukankan      html  css  js  c++  java
  • 并发编程 --- 进程,线程

    进程

    1.进程互斥锁

    异步可以让多个任务在几个进程中并发处理,他们之间没有运行顺序,一旦开启也不受我们的控制,尽管并发编程让我们更加充分的利用IO资源,但是当多个进程使用同一份资源的时候,就会引发数据安全或顺序混乱的问题

    import json
    import time
    from multiprocessing import Process
    from multiprocessing import Lock
    
    
    # 查看余票
    def search(user):
        # 打开data文件查看余票
        with open('data.txt', 'r', encoding='utf-8') as f:
            dic = json.load(f)
        print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}...')
    
    
    # 开始抢票
    def buy(user):
        # 先打开获取车票数据
        with open('data.txt', 'r', encoding='utf-8') as f:
            dic = json.load(f)
    
        # 模拟网络延时
        time.sleep(1)
    
        # 若有票,修改data数据
        if dic.get("ticket_num") > 0:
            dic['ticket_num'] -= 1
            with open('data.txt', 'w', encoding='utf-8') as f:
                json.dump(dic, f)
            print(f'用户: {user}抢票成功!')
    
        else:
            print(f'用户: {user}抢票失败!')
    
    
    # 开始抢票
    def run(user, mutex):
        # 并发: 异步执行
        search(user)
    
        # 串行: 同步执行
        mutex.acquire()
        buy(user)
        mutex.release()
    
    
    if __name__ == '__main__':
        # 调用Lock()类得到一个锁对象
        mutex = Lock()
    
        # 同时来10个用户抢票
        for i in range(10):
            # 并发开启10个子进程
            p = Process(target=run, args=(f'用户{i}', mutex))
            p.start()
    

    2.队列

    1.队列的概念

    创建一个共享的进程队列,可以使用Queue实现对进程之间的数据传递。

    2.队列的使用方法
    from multiprocessing import Queue
    
    # 调用队列类,实例化队列对象
    q = Queue(5)   # 5指的是队列中可以存放五个参数,如果不穿参,可以放无限个参数,前提是硬件能跟得上
    
    # 添加队列
    q.put(1)   # 变量1传入队列中,如果队列已经添加满了,就会卡住
    
    # 判断队列是否位空
    print(q.empty())  # 返回位True为空,False不为空
    
    # 取出队列
    print(q.get())    # 获取数据遵循‘先进先出’,若队列中无数据可取,也会卡住
    
    # 取数据时不卡住
    print(q.get_nowait())  # 没有数据的时候会报错。
    
    # 查看队列是否满了 
    print(q.full())   # 满了为True,没有满位False
    
    

    3.进程之间的通信

    进程之间的数据是相互隔离的,要想实现进程间的通信(IPC),可以使用multiprocessing模块中的队列和管道,这两种方法是可以实现进程间数据传输的,由于队列是管道+锁的方式实现的,所以我们着重研究队列。

    from multiprocessing import Process,Queue
    
    def producer(q):
        q.put('hello big baby')
    
    def consumer(q):
        print(q.get())
    
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=producer,args=(q,))
        p1 = Process(target=consumer,args=(q,))
    
        p.start()
        p1.start()
        
     # 输出为 hello big baby
    

    4.生产者与消费者

    生产者:生产数据的

    消费者:消费数据的

    线程

    1.什么是线程

    线程与进程都是虚拟单位,目的是为了更好的描述某种事物

    进程:资源单位

    线程:执行单位

    开启一个进程,一定会有一个线程,线程才是真正的执行者,

    2.为什么要使用线程

    为了节省内存资源

    开启进程会发生的两件事情:

    1.开辟一个名称空间,每开启一个进程空间,都会占用一份内存资源,

    2.会自带一个线程,

    开启线程:

    1.一个进程可以开启多个线程,

    2.线程的开销远小于进程

    注意:线程不能实现并行,线程只能实现并发,进程可以实现并行。

    3.线程两种创建方式

    进程不能直接在import下直接调用,线程可以。

    # 开启线程方式1:
    from threading import Thread
    import time
    def task():
        print('线程开启')
        time.sleep(1)
        print('线程结束')
    
    if __name__ == '__main__':
        t = Thread()
        t = Thread(target=task)
        t.start()
        print('主')
    
    
    # 开启线程方式2:
    from threading import Thread
    import time
    
    class Sayhi(Thread):
        def __init__(self,name):
            super().__init__()
            self.name = name
        def run(self):
            time.sleep(2)
            print(self.name)
    
    if __name__ == '__main__':
        t = Sayhi('wang')
        t.start()
        print('主')
    

    内存就像一个工厂,子进程就像一个工厂车间,线程就像车间内的流水线

    4.线程对象的属性

    线程之间的数据是共享的

    5.守护线程

    无论是进程还是线程,都遵循:守护xxx会等待主xxx运行结束完毕之后被销毁,需要强调的是运行完毕并非终止运行

    from threading import Thread
    import time
    
    def say(name):
        time.sleep(1)
        print(name)
    
    if __name__ == '__main__':
        t = Thread(target=say,args=('wang',))
        t.setDaemon(True)
        t.start()
    
        print('主进程')
        print(t.is_alive())
    

    6.线程互斥锁

    from threading import Thread, Lock
    import time
    
    mutex = Lock()
    
    n = 100
    
    
    def task(i):
        print(f'线程{i}启动...')
        global n
        # mutex.acquire()
        temp = n
        time.sleep(0.1)  # 一共等待10秒
        n = temp-1
        print(n)
        # mutex.release()
    
    
    if __name__ == '__main__':
        t_l=[]
        for i in range(100):
            t = Thread(target=task, args=(i, ))
            t_l.append(t)
            t.start()
    
        for t in t_l:
            t.join()
    
        # 100个线程都是在100-1
        print(n)
    
  • 相关阅读:
    RSA加密
    各种正则
    用Fragment制作的Tab页面产生的UI重叠问题
    Android源码下载
    Android Studio使用百度地图问题总结
    Android获取网络类型
    Android Studio类中实现Serializable自动生成serialVersionUID
    【Android开发】如何设计开发一款Android App
    UIViewController生命周期
    微信支付开发经验分享
  • 原文地址:https://www.cnblogs.com/whkzm/p/11722083.html
Copyright © 2011-2022 走看看