多进程和多线程复习

定义

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

区别

  1. 一个程序至少有一个进程,一个进程至少有一个线程.
  2. 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
  3. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
  4. 线程不能够独立执行,必须依存在进程中
  • 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。

1、 多线程案例

udp多人聊天

# -*- coding:utf-8 -*-


import socket
import threading

def send_msg(udp_socket):
    while True:
        # 1. 从键盘输入数据
        msg = input("\n请输入要发送的数据:\n")
        # 2. 输入对方的ip地址
        dest_ip = input("\n请输入对方的ip地址:\n")
        # 3. 输入对方的port
        dest_port = int(input("\n请输入对方的port:\n"))
        # 4. 发送数据
        udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))


def recv_msg(udp_socket):
    '''接收数据'''
    while True:
        #接收数据
        recv_msg = udp_socket.recvfrom(1024)
        #解码
        recv_ip = recv_msg[1]
        recv_msg = recv_msg[0].decode('utf8')
        print('%s:%s'%(str(recv_ip),recv_msg))

def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    #绑定
    udp_socket.bind(('',7788))
    #创建子线程接收数据
    t = threading.Thread(target=recv_msg,args=(udp_socket,))
    t.start()
    #主线程用来检测键盘数据并且发送
    send_msg(udp_socket)


if __name__ == "__main__":
    main()

# 创建锁
mutex = threading.Lock()

# 锁定
mutex.acquire()

# 释放
mutex.release()
  • 锁的好处:

    确保了某段关键代码只能由一个线程从头到尾完整地执行

  • 锁的坏处:

阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁

  • 避免死锁

程序设计时要尽量避免(银行家算法)
添加超时时间等

2、多进程

  • multiprocessing.Pool常用函数解析:
  • apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
  • close():关闭Pool,使其不再接受新的任务;
  • terminate():不管任务是否完成,立即终止;
  • join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;

文件拷贝

# -*- coding:utf-8 -*-

import multiprocessing
import os,time,random


def copy_file(queue,file_name,source_folder_name,dest_folder_name):
    f_read = open(source_folder_name + '/' + file_name,'rb')
    f_write = open(dest_folder_name + '/' + file_name,'wb')
    while True:
        content = f_read.read(1024)
        if content:
            f_write.write(content)
        else:
            break
    f_read.close()
    f_write.close()

    # 发送已经拷贝完毕的文件名字
    queue.put(file_name)

def main():
    # 获取要复制的文件夹
    source_folder_name = r'H:\学习\test'
    # 整理目标文件夹
    dest_folder_name = source_folder_name + '副本'
    #创建目标文件夹
    try:
        os.mkdir(dest_folder_name)
    except:
        pass
    #获取这个文件夹的所有文件名
    file_names = os.listdir(source_folder_name)
    #创建Queue
    queue = multiprocessing.Manager().Queue()
    #创建进程池
    pool = multiprocessing.Pool(3)
    for file_name in file_names:
        pool.apply_async(copy_file,args=(queue,file_name,source_folder_name,dest_folder_name))

    pool.close() #不再接收新的任务
    #主进程显示进度

    all_filenum = len(file_names)
    while True:
        file_name = queue.get()
        if file_name in file_names:
            file_names.remove(file_name)

        copy_rate = (all_filenum - len(file_names)) * 100/all_filenum
        print("\r%.2f...(%s)" % (copy_rate, file_name) + " " * 50, end="")
        if copy_rate >= 100:
            break
    print()

if __name__ == '__main__':
    main()


3、协程

属于并发

# -*- coding:utf-8 -*-
from gevent import monkey
import gevent
import urllib.request

# 有耗时操作时需要
monkey.patch_all()

def my_downLoad(url):
    print('GET: %s' % url)
    resp = urllib.request.urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(my_downLoad, 'http://www.baidu.com/'),
        gevent.spawn(my_downLoad, 'https://www.csdn.net/'),
        gevent.spawn(my_downLoad, 'https://y.qq.com/'),
])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值