十六、多任务

多任务

import threading

def dance():
    for i in range(50):
        print('我正在跳舞')

def sing():
    for i in range(50):
        print('我正在唱歌')

# 多个任务同时执行
# Python里执行多任务:多线程、多进程、多进程+多线程
dance()
sing()

# target 需要的是一个函数,用来指定线程需要执行的任务
t1 = threading.Thread(target=dance()) # 创建了线程1
t2 = threading.Thread(target=sing()) # 创建了线程2

# 启动线程
t1.start()
t2.start()

二、线程

2.1 多线程聊天

import socket, threading
s = socket.socket(AF_INET, socket.SPCK_DGRAM)
s.bind(('192.168.31.180', 9090))

def send_msg():
    while True:
        content = input('请输入要发生的信息:')
        s.sendto(content.encode('utf8'),('192.168.31.199', 9000))

def rec_msg():
    while True:
        content = s.recvfrom(1024).decode('utf8')
        print(content)

t1 = threading.Thread(target=send_msg)  # 创建线程1
t2 = threading.Thread(target=rec_msg)  # 创建线程2

t1.start()
t2.start()

2.2 多个线程共享全局变量

import threading


# 多个线程可以同时操作一个全局变量(多个线程共享全局变量)
# 线程安全问题
ticket = 20

def sell_ticket():
    global ticket
    while True:
        if ticket > 0:
            ticket -= 1
            print(f'{threading.current_thread().name}卖出一张票,还剩{ticket}张')
        else:
            print('票买完了')
            break

t1 = threading.Thread(target=sell_ticket, name='线程1')
t2 = threading.Thread(target=sell_ticket, name='线程2')

t1.start()
t2.start()

2.3 线程锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行 同步控制。同步就是协同步调,按预定的先后次序进行运行。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制就是引入互斥锁

import threading

# 多个线程可以同时操作一个全局变量(多个线程共享全局变量)
# 线程安全问题
ticket = 20

# 创建一把锁
lock = threading.Lock()

def sell_ticket():
    global ticket
    while True:
        lock.acquire()  # 加同步锁
        if ticket > 0:
            ticket -= 1
            print(f'{threading.current_thread().name}卖出一张票,还剩{ticket}张')
            lock.release()
        else:
            lock.release()
            print('票买完了')
            break

t1 = threading.Thread(target=sell_ticket, name='线程1')
t2 = threading.Thread(target=sell_ticket, name='线程2')

t1.start()
t2.start()

2.4 线程间通信

import threading, queue

def produce():
    for i in range(10):
        p.put(f'b{i}')
        print(f'{threading.current_thread().name}生产了面包 b{i}')

def consumer()
    for i in range(100):
        # q.get() 方法是一个阻塞的方法,即队列内没有数据则一直等待至有数据为止
        print(f'{threading.current_thread().name}消费了面包{q.get()}')

q = queue.Queue() # 创建一个q
p1 = threading.Thread(target=produce, name = 'p1')
c1 = threading.Thread(target=consumer, name = 'c1')

p1.start()
c1.start()

三、进程

3.1 进程简介

程序:例如 XXX.py 这是程序,是一个静态的
进程:一个程序运行起来后,代码+用到的资源 称之为进程,他是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程也是可以的

3.2 进程的状态

工作中,任务数往往大于cpu的核数,即一定有一些任务可以执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态

  • 就绪态:运行的条件都已经满足,正在等在cpu执行
  • 执行态:cpu正在执行其功能
  • 等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态

3.3 多进程

import multiprocessing, os
def dance(n):
    for i in range(n):
        print(f'正在跳舞{i},pid={os.getpid()}')

def sing(m):
    for i in range(m):
        print(f'正在唱歌{i},pid={os.getpid()}')

if __name__ = '__main__':
    # 创建了两个进程
    # target 用来表示执行的任务
    # args 用来传参,类型是一个元组
    p1 = multiprocessing.Process(target=dance, args=(20,))
    p2 = multiprocessing.Process(target=sing, args=(50,))
    
    p1.dance()
    p2.sing()

3.4 线程和进程的区别

  • 功能

    • 进程:能够完成多任务,比如 在一台电脑上运行多个qq
    • 线程:能够完成多任务,比如 一个QQ中的多个聊天窗口
  • 定义不同

    • 进程是系统进行资源分配和调度的一个独立单位
    • 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源
  • 区别

    • 一个程序至少有一个进程,一个进程至少有一个线程
    • 线程的划分尺度小于进程(资源比进程少),使得多线程程序并发性高
    • 进程在执行过程中拥有独立的内存单元,而多线程共享内存,从而极大地提高了程序的运行效率
    • 线程不能单独执行,必须依存在进程中
    • 可以将进程理解为工厂的一条流水线,而其中的线程就是这个流水线上的工人
  • 优缺点
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反
    在这里插入图片描述

3.5 进程不共享全局变量

import os, threading, multiprocessing

n = 100

def test():
    global n
    n += 1
    print('{os.getpid()} n的值是{n}')

def demo():
    global n
    n += 1
    print('{os.getpid()} n的值是{n}')

# test() # 101
# test() # 102

# 同一个主进程里的两个子线程。线程之间可以共享同一进程的全局变量
# t1 = threading.Thread(target=test)
# t2 = threading.Thread(target=demo)
# t1.start()
# t2.start()

if __name__ = '__main__':
    # 不同进程各自保存一份全局变量,不会共享全局变量
    p1 = multiprocessing.Process(target=test)
    p2 = multiprocessing.Process(target=demo)
    p1.start() # 
    p2.start() # 

3.6 进程间通信

import os, multiprocessing

def producer(q):
    for i in range(10):
        print(f'生产了+++++pid{os.getpid()} {i}')
        q.put(f'pid{os.getpid()} {i}')

def consumer(q):
    for i in range(10):
        print(f'消费了---------{q.get()}')

if __name__ == '__main__':
    q = multiprocessing.Queue()
    
    p1 = multiprocessing.Process(target=producer, args=(q,))
    c1 = multiprocessing.Process(target=consumer,args=(q,))
    
    p1.start()
    c1.start()

3.7 queue队列

import multiprocessing, queue

# q1 = multiprocessing.Queue() # 进程间通信
# q2 = queue.Queue() # 线程间通信

# 创建队列时,可以指定最大长度。默认值是0,表示不限
q = multiprocessing.Queue(5)
q.put('a')
q.put('b')
q.put('c')
q.put('d')
q.put('e')

# print(q.full()) # True 判断当前队列是否满队列
# q.put('f') # 无法放进去,会阻塞当前线程

# block = True:表示是阻塞,如果队列已经满了,就等待
# timeout  超时,等待多久以后程序会出错,单位是秒
# q.put('how', block=True)

q.put_nowait('how') # 等价于  q.put('how',block=False)

print(q.get()) # a
print(q.get()) # b
print(q.get()) # c
print(q.get()) # d
print(q.get()) # e
# q.get() # 默认队列取空了会阻塞等待
# q.get(block=True, timeout = 10)
q.get_nowait() # 等价于q.get(block=False)

3.8 进程池

当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程,但如果是上百个甚至上千个目标,手动的取创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法
初始化Pool时,可以指定一个最大进程数,当有新的骑牛提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务

from multiprocessing import Pool
import os, time, random

def worker(msg):
    t_start = time.time()
    print(f"{msg}开始执行,进程号为{os.getpid()}")
    # random.random()随机生成0~1之间的浮点数
    time.sleep(random.random() * 2)
    t_stop = time.time()
    print(f"{msg} 执行完毕,耗时{t_stop - s_start}")

if __name__ = '__main__'
    po = Pool(3) # 定义一个进程池,最大进程数3
    for i in range(0, 10):
        # Pool().apply_async(要调用的目标,(传递给目标的参数元组,))
        # 每次循环将会用进程池中空闲出来的子进程去调用目标
        po.apply_async(worker,(i,))

    print("----start----")
    po.close() # 关闭进程池,关闭后 po 不在接收新的请求

3.9 join方法的使用

# join 线程和进程都有 join方法
import time

x = 10

def test(a, b):
    time.sleep(1)
    global x
    x = a + b
# test(1, 1)
# print(x) # 2

t = threading.Thread(target=test,args=(1,1))
t.start()

t.join() # 让主线程等待子线程执行完毕

print(x) # 若没有 t.join() 则为10,否则为 2
  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ModelBulider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值