Python的多线程
连接有关于线程模块的的使用方式,但是个人认为作为多任务的实现方式,该链接不完整。
链接地址:http://www.runoob.com/python3/python3-multithreading.html
文章主要包含的是 多任务
的创建以及处理方式,及其相关的定义问题。
- 进程
- 进程是一个进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行
资源分配
和调度的基本单位
。程序是指令、数据及其组织形式的描述,进程是程序的实体。
- 进程是一个进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行
- 线程
- 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是
系统独立调度
和分派的基本单位
。
- 线程,有时被称为轻量进程(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
# 二者貌似没有太大的差别,前者是直接迭代到我们需要的结果;
# 后者是保留需要的完整列表,目的是获得数列,方便后续的调用,提高复用度.