多线程&多任务

Python的多线程

连接有关于线程模块的的使用方式,但是个人认为作为多任务的实现方式,该链接不完整。

链接地址:http://www.runoob.com/python3/python3-multithreading.html

文章主要包含的是 多任务 的创建以及处理方式,及其相关的定义问题。

  • 进程
    • 进程是一个进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配调度的基本单位。程序是指令、数据及其组织形式的描述,进程是程序的实体。
  • 线程
    • 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是系统独立调度分派的基本单位
  • 协程
    • 协程(coroutine)也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。

以上的表述摘自于百度百科,显然就一个问题:操作系统的地调度的基本单位是什么?二者有不同的解读,我个人坚持:进程是操作系统调度和资源分配的基本单位,是一个线程的容器,容器内部公用部分资源达到提高CPU使用效率的目的。

利用Thread模块实现的多任务

  • 通过threading.Thread实现
# 就效果而言是可以通过time的sleep,实现有序访问的,但是容易留下祖传代码.
import threading
import time


def test_one():
    for i in range(3):
        mutex.acquire()
        print("--test_one():--%d--" % i)
        mutex.release()
        time.sleep(0.5)


def test_two():
    for i in range(3):
        mutex.acquire()
        print("--test_two():--%d--" % i)
        mutex.release()
        time.sleep(0.5)


def main():
    threading_01 = threading.Thread(target=test_one)
    threading_02 = threading.Thread(target=test_two)
    threading_01.start()
    threading_02.start()


mutex = threading.Lock()
if __name__ == "__main__":
    main()
# print(threading.enumerate()),或许线程的信息,保存为列表。
# 多线程的UDP_收发包函数功能.
import socket
import threading
import time #sleep函数可略.

# 解包函数.
def recv_msg(udp_socket):
    while True:
        time.sleep(0.1)
        recv_data = udp_socket.recvfrom(1024)
        print(recv_data)

#发包函数.
def send_msg(udp_socket, dest_ip, dest_port):
    while True:
        time.sleep(0.1)
        send_data = input("输入要发送的数据:")
        udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))


def main():
    """完成ip&端口的配置"""
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(("", 10500))
    dest_ip = input("Connect to IP:")
    dest_port = int(input("Connect to port:"))
    # 多线程启动...
    # 为保证是元组,只有一个参数,需要参数后面添加逗号.
    t_recv = threading.Thread(target=recv_msg, args=(udp_socket,))
    t_send = threading.Thread(target=send_msg, args=(udp_socket, dest_ip, dest_port))
    t_recv.start()
    t_send.start()


if __name__ == "__main__":
    main()
  • 通过multiprocessing实现
# 经过对比发现二者的近乎完全一致.
import time
import multiprocessing


def test_one():
    while True:
        print("test_one...")
        time.sleep(1)


def test_two():
    while True:
        print("test_two...")
        time.sleep(1)


def main():
    ps_one = multiprocessing.Process(target=test_one)
    ps_two = multiprocessing.Process(target=test_two)


    ps_one.start()
    ps_two.start()

if __name__ == "__main__":
    main()
  • 继承Thread实现的多线程
import threading
import time


class test_one(threading.Thread):
    def run(self):
        for i in range(10):                       
            print("test_one:%d" % i)
            time.sleep(0.5)
    


class test_two(threading.Thread):
    def run(self):
        for i in range(10):
            print("test_one:%d" % i)
            time.sleep(0.5)
    

def main():
    ps_01 = test_one()
    ps_02 = test_two()
    ps_01.start()
    ps_02.start()

if __name__ == "__main__":
    main()


multiprocessing实现的多任务-文件夹复制

  • 线程池的使用

  • 基本的流程如下:

    • 定义进程池
    • 分配/启动进程池
    • 关闭入口
    • 将主进程加入子进程之后.
    pool = Pool(num)
    	pool.apply_async(target,args)
    pool.close()
    pool.join # 主进程加入.
    
  • 实现文件夹的复制-且显示文件复制的进度条

  • 流程如下:

    • 获取需要复制的文件夹&文件列表
    • 遍历文件夹的目录列表,实现复制.
    • 完成一个文件实现文件共享变量数值+1.
    • 利用共享的变量/总的文件个数,实现文件完成百分比.
    # -*- coding:utf-8 -*-
    from multiprocessing import Pool
    import os, time, random
    
    def worker(msg):
        t_start = time.time()
        print("%s开始执行,进程号为%d" % (msg,os.getpid()))
        # random.random()随机生成0~1之间的浮点数.
        time.sleep(random.random()*2)
        t_stop = time.time()
        print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start))
    
    po = Pool(3)  # 定义一个进程池,最大进程数3.
    for i in range(0,7):
        po.apply_async(worker,(i,))
    
    print("----start----")
    po.close()  # mark_01
    print("你的位置...")
    po.join()  # mark_02 两处标记不可交换,只能是join在close函数之后.
    print("告诉我,你的位置....")
    print("-----end-----")
    
    """
    result:
    /home/pc-gmxy/socket/venv/bin/python /home/pc-gmxy/socket/进程池.py
    ----start----
    你的位置...
        ...进程部分...
    告诉我,你的位置....
    -----end-----
    """
    

利用yield生成器实现的多任务

详细的使用文档:http://www.runoob.com/w3cnote/python-yield-used-analysis.html

  • 利用yield的生成器实现的多任务,或者叫做多线程,其实是非常微妙的,有关键点在于执行到yield的时候,运行会返回一个值。

  • 简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!也就是说,只要含有yield就是一个生成器。

  • 在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield,于是就可以变成手动实现的迭代器…

  • yield实现的多任务

import time

def task_01():
    while True:
        print("---1----")
        time.sleep(0.5)
        yield

def task_02():
    while True:
        print("---2----")
        time.sleep(0.5)
        yield

def main():
    ps_01 = task_01()
    ps_02 = task_02()
    while True:
        next(ps_01)
        next(ps_02)

if __name__ == "__main__":
    main()

gevent实现的多任务-yield

迭代器

  • 自己手动实现的迭代器

有next等完整的数据结构,表明是可以迭代的对象.

import time

class Classmate(object):
    def __init__(self):
        # 创建一个列表.
        self.names = list()
        self.current_num = 0

    def add(self, name):
        self.names.append(name)

    def __iter__(self):       
        return self 

    def __next__(self):
        if self.current_num < len(self.names):
            ret = self.names[self.current_num]
            self.current_num += 1
            return ret
        else:
            raise StopIteration


classmate = Classmate()
classmate.add("老大")
classmate.add("老二")
classmate.add("老三")

for name in classmate:
    print(name)
    time.sleep(0.5)
  • 菲波那切数列
#!/usr/bin/python
# -*- coding: UTF-8 -*-

# 第一行的目的是可以实现在类unix下可以直接运行该文件,第二行是编码格式说明.

# mark_01
class Fab(object):  
    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 
 
    def __iter__(self): 
        return self 
 
    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration() # 手动添加异常,后续捕捉到该异常可以正确处理.
 
for n in Fab(5): 
    print n

# mark_02
def fab(max): 
    n, a, b = 0, 0, 1 
    L = [] 
    while n < max: 
        L.append(b) 
        a, b = b, a + b 
        n = n + 1 
    return L
 
for n in fab(5): 
    print n
# 二者貌似没有太大的差别,前者是直接迭代到我们需要的结果;
# 后者是保留需要的完整列表,目的是获得数列,方便后续的调用,提高复用度.

猜你喜欢

转载自blog.csdn.net/CS_GaoMing/article/details/85276318