多线程模块
描述详情可看这https://www.cnblogs.com/wkhzwmr/p/15243363.html
当初也忘了为何要把代码从仓库复制到这来,之前已经写过了
类模块
import threading
from time import sleep, ctime
# 从Thread类派生的子类
# class MyThread(threading.Thread):
# # 重写父类的构造方法,其中func是线程函数,args是传入线程函数的参数,name是线程名
# def __init__(self, func, args, name=''): # 这里主要构造的就是相应的传入参数的值吧,还有传入值的顺序
# # 调用父类的构造方法,并传入相应的参数值
# super().__init__(target=func, name=name,
# args=args)
# # 重写父类的run方法
# def run(self):
# self._target(*self._args)
class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
super().__init__(target=func,args=args,name=name)
def run(self):
self._target(*self._args) # self._args与self.args的区别
# 线程函数
def fun(index, sec):
print('开始执行', index, '时间:', ctime())
# 休眠sec秒
sleep(sec)
print('执行完毕', index, '时间:', ctime())
def main():
# 这个多线程如何运用在具体的爬虫环境中呢
print('开始:', ctime())
# 创建第1个线程,并指定线程名为“线程1”
thread1 = MyThread(fun, (10, 4), '线程1')
# 创建第2个线程,并指定线程名为“线程2”
thread2 = MyThread(fun, (20, 2), '线程2')
# 开启第1个线程
thread1.start()
# 开启第2个线程
thread2.start()
# 输出第1个线程的名字
print(thread1.name)
# 输出第2个线程的名字
print(thread2.name)
# 等待第1个线程结束
thread1.join()
# 等待第2个线程结束
thread2.join()
print('结束:', ctime())
if __name__ == '__main__':
main()
消费者模型
'''
这个消费者模型只执行了两次
'''
from random import randrange
from time import sleep,time, ctime
from threading import Lock, Thread
from queue import Queue
# 创建线程锁对象
lock = Lock()
# 从Thread派生的子类
class MyThread(Thread):
def __init__(self, func, args):
super().__init__(target = func, args = args)
# 向队列中添加商品
def writeQ(queue):
# 获取线程锁
lock.acquire()
print('生产了一个对象,并将其添加到队列中', end=' ')
# 向队列中添加商品
queue.put('商品')
print("队列尺寸", queue.qsize())
# 释放线程锁
lock.release()
# 从队列中获取商品
def readQ(queue):
# 获取线程锁
lock.acquire()
# 从队列中获取商品
val = queue.get(1)
print('消费了一个对象,队列尺寸:', queue.qsize())
# 释放线程锁
lock.release()
# 生成若干个生产者
def writer(queue, loops):
for i in range(loops):
writeQ(queue)
sleep(randrange(1, 4))
# 生成若干个消费者
def reader(queue, loops):
for i in range(loops):
readQ(queue)
sleep(randrange(2, 6))
funcs = [writer, reader]
nfuncs = range(len(funcs))
def main():
nloops = randrange(2, 6)
q = Queue(32)
threads = []
# 创建2个线程运行writer函数和reader函数
for i in nfuncs:
t = MyThread(funcs[i], (q, nloops))
threads.append(t)
# 开始线程
for i in nfuncs:
threads[i].start()
# 等待2个线程结束
for i in nfuncs:
threads[i].join()
print('所有的工作完成')
if __name__ == '__main__':
main()
糖果机
from atexit import register
from random import randrange
from threading import BoundedSemaphore, Lock, Thread
from time import sleep, ctime
'''
本例通过信号量和线程锁模拟一个糖果机补充糖果和用户取得糖果的过程,
糖果机有5个槽,如果发现每个槽都没有糖果了,需要补充新的糖果。
当5个槽都满了,就无法补充新的糖果了,如果5个槽都是空的,顾客也无法购买糖果了。
为了方便,本例假设顾客一次会购买整个槽的糖果,每次补充整个槽的糖果。
'''
# 创建线程锁
lock = Lock() # 全局变量
# 定义糖果机的槽数,也是信号量计数器的最大值
MAX = 5
# 创建信号量对象,并指定计数器的最大值
candytray = BoundedSemaphore(MAX)
# 给糖果机的槽补充新的糖果(每次只补充一个槽)
def refill():
# 获取线程锁,将补充糖果的操作变成原子操作
lock.acquire()
print('重新添加糖果...', end=' ')
try:
# 为糖果机的槽补充糖果(计数器加1)
candytray.release()
except ValueError:
print('糖果机都满了,无法添加')
else:
print('成功添加糖果')
# 释放线程锁
lock.release()
# 顾客购买糖果
def buy():
# 获取线程锁,将购买糖果的操作变成原子操作
lock.acquire()
print('购买糖果...', end=' ')
# 顾客购买糖果(计数器减1),如果购买失败(5个槽都没有糖果了),返回False
if candytray.acquire(False):
print('成功购买糖果')
else:
print('糖果机为空,无法购买糖果')
# 释放线程锁
lock.release()
# 产生多个补充糖果的动作
def producer(loops): # 使用for循环补充,多次重复一个动作
for i in range(loops):
refill()
sleep(randrange(3))
# 产生多个购买糖果的动作
def consumer(loops):
for i in range(loops):
buy()
sleep(randrange(3))
def main():
print('开始:', ctime())
# 参数一个2到5的随机数
nloops = randrange(2, 6)
print('糖果机共有%d个槽!' % MAX)
# 开始一个线程,用于执行consumer函数
Thread(target=consumer, args=(randrange(
nloops, nloops+MAX+2),)).start()
# 开始一个线程,用于执行producer函数
Thread(target=producer, args=(nloops,)).start()
@register
def exit():
print('程序执行完毕:', ctime())
if __name__ == '__main__':
main()
线程池
import multiprocessing.dummy # 该模块作用是复制了multiprocessing模块的API
import time
# 多线程实现线程池的方法和多进程实现进程池的方法一样
def process_func(process_id):
print("process id %d start" % process_id)
time.sleep(3)
print("process id %d end"% process_id)
def main():
#虽然参数叫processes但是实际创建的是线程
pool = multiprocessing.dummy.Pool(processes=3)
for i in range(10):
# 向进程池中添加要执行的任务
# apply_asyns这个函数的作用是什么,asyns经常在服务器中碰到这个词;写错了,报错,是async
pool.apply_async(process_func,args=(i,))
pool.close()
pool.join()
if __name__ == "__main__":
main()
多进程模块
subprocess模块
import os
import subprocess
if os.name == "nt":
return_code = subprocess.call(["cmd","/C","dir"]) # 尽然一定要cmd /C 开头才能执行 dir命令,没有os.system方便
else:
return_code = subprocess.call("ls")
if return_code == 0:
print("Run success")
else:
print("Some Wrong")
多进程之间的通信
from multiprocessing import Process,Queue
import os
import queue
# 创建队列
result_queue = Queue()
class MyProcess(Process):
def __init__(self,q):
super(MyProcess,self).__init__()
# 获取队列
self.q = q
def run(self):
output = "module name %s\n"%__name__#这样就可以打印出名字
output +="parent process%d\n"%os.getppid()# 获取父进程
output +="process id%d"%os.getpid()
self.q.put(output)
def main():
processes = []
# 创建进程并把队列传递给进程
for i in range(5):
processes.append(MyProcess(result_queue))
# 启动进程
for i in range(5):
processes[i].start()
# 等待进程结束
for i in range(5):
processes[i].join()
while not result_queue.empty():
output = result_queue.get()
print(output)
if __name__ == "__main__":
main() # 多了两个进程,这个创建了进程不会在系统中推出的
多进程初试
from multiprocessing import Pool
import time
# 进程回调函数
def get_value(value):
i = 0
while i < 3:
# 休眠1秒
time.sleep(1)
print(value,i)
i += 1
if __name__ == '__main__':
# 产生5个值,供多进程获取
values = ['value{}'.format(str(i)) for i in range(0,5)]
values1 = ['value{}'.format(str(i)) for i in range(10,15)]
# 创建4个进程;进程池
pool = Pool(processes=4)
# 将进程回调函数与values关联
pool.map(get_value,values)
pool.map(get_value,values1)
多进程的子进程创建
from multiprocessing import Process # 这与process有啥区别
import os
def info(title):
print(title)
print("module name ",__name__) #这样就可以打印出名字
print("parent process:",os.getppid()) # 获取父进程
print("process id",os.getpid())
def f(name):
info('function f')
print("hello",name)
# 搞不懂这是如何创建子进程的
if __name__ == "__main__":
info("main line")
p = Process(target=f,args=('jj',))
p.start()
p.join()
重新编写多进程的类
from multiprocessing import Process#process
import os
class MyProcess(Process):
def __init__(self):
super(MyProcess,self).__init__() # 这句啥意思,要从继承里查看么
def run(self):
print("module name ",__name__) #这样就可以打印出名字
print("parent process:",os.getppid()) # 获取父进程
print("process id",os.getpid())
def main():
processes = []
# 创建进程
for i in range(5):
processes.append(MyProcess())
# 启动进程
for i in range(5):
processes[i].start()
# 等待进程结束
for i in range(5):
processes[i].join() # 保护进程安全么
if __name__ == "__main__":
main()