首页 > 编程语言 >Python进阶三

Python进阶三

时间:2023-05-29 19:22:30浏览次数:35  
标签:__ 进阶 Python 创建 print 线程 进程 name

进程和线程

一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程;在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,把进程内的这些“子任务”称为线程(Thread),比如Word,它可以同时进行打字、拼写检查、打印等事情。线程是最小的执行单元,而进程由至少一个线程组成。
同时执行多个任务:

  1. 多进程模式:是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
  2. 多线程模式:是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
  3. 多进程+多线程模式:启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。
    计算量大的用多线程,需要读取多的用多进程。

多进程

程序每次执行时,操作系统就会创建一个新的进程来运行程序指令。
在下面的fork()函数运行的时候,fork()函数会复制当前这个进程,然后创建一个子进程。
普通的函数调用就是调用一次,返回一次。但fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。
子进程永远返回0,而父进程返回子进程的ID。一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

import os
print('Process (%s) start...' % os.getpid())
pid = os.fork()
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))

os.getpid()返回当前进程的ID
os.getppid()返回父进程的ID,有两个p。
这些代码只能在mac和Linux系统上面运行,window运行会报错,因为没有fork()这个方法。
从pid=os.fork()这行里,开始创建了两个进程,就是两个任务,一个是父进程返回的是子进程的ID,而子进程只会返回0,于是两个任务就分别进入if和else语句。但是先打印哪句话(先运行父进程还是子进程,这个是由操作系统决定的)进程调度是操作系统决定的,千万不要在代码里假定哪个先执行
在windows里,因为没有fork()函数,所以引入multiprocessing模块的Precess类来创建进程对象。
还有一个就是必须得写if name=='main':这个程序入口,不然会陷入无限递归,然后保存。

from multiprocessing import Process
import os

# 子进程要执行的代码(就是任务函数)
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

#这里面没有fork()函数来复制当前进程来创建一个子进程
if __name__=='__main__':#这个__name__='__main__'跟包的引入有关,就记得是程序的入口就行
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))#所以就自己创建一个子进程,这句话就是自己创建一个子进程的意思
    print('Child process will start.')
    p.start()#启动自己创建的子进程
    p.join()
    print('Child process end.')

这里面着重p = Process(target=run_proc, args=('test',))这句话,当创建一个进程,里面需要执行任务,所以target参数就是可以传入需要这个进程执行的代码名,后面的参数args,就是传入的任务函数的参数。创建了进程对象,需要调用start()方法来启动这个进程。

错误抛出:
Python 解释器在 Windows平台 执行创建多进程的程序时,子进程会读取当前 Python 文件,用以创建进程。
在子进程读取当前文件时,读取到创建子进程的代码时又会创建新的子进程,这样程序就陷入递归创建进程的状态。
由于 Python 解释器中对于创建子进程有一个最大数量限制来保护我们的计算机,防止其内存溢出,因此程序会抛出异常。
所以创建进程必须得写if name=='main':这个程序入口里,不然会陷入无限递归,然后保存。

进程池pool

进程池就是可以一下子创建好几个进程在这个池子对象里,然后用这个池子对象执行任务,这个池子对象就会用几个进程来执行任务。
p = Pool(5),就是创建5个进程,但是一般电脑的CPU都是四核的,所以就会等执行完一个进程,再去执行第五个进程。所以进程池创建几个进程就会调用CPU的几个核,要是多于CPU的核,就会等某个进程结束,再执行。

import multiprocessing as mp
import os

def job(x):
    return x*x


if __name__ == "__main__":
    print("当前进程启动,不是池子里创建的进行,这是个父进程%s"%os.getpid())
    p = mp.Pool(5)#这句就是在进程池里创建了5个进程,但是我的电脑CPU里只有四个核
    res = p.map(job,range(5))#这个map跟python内置的map用法一样,不同的是自己会返回列表格式
    print(type(res))
    print(res)


这个就是简单的使用进程池来创建多线程对Job函数使用多个核来执行。
除了pool的map方法,还有一个apply_async(job,(参数,))方法,它同样需要传入任务函数名,必须要在参数后面加逗号,而且必须加括号,说明是个元组(弹幕里说的,还是不能理解),但是不能传入好几个参数,只能传入一个参数,如果要传多个,需要用到列表解析式。
而且要这个apply_async()返回的是一个类对象,必须使用get()才能获取到值。

要apply_async能处理多个参数的()需要使用列表解析式:
由于这个函数只能返回一个类对象,调用get()方法才能获得值,所以用来列表解析式获取的列表里面包含的都是不同的类对象,所以需要再写一个列表解析式迭代这个里面都是类对象的列表,才能获取返回值。

还有一个join()方法,说是阻塞主进程,当调用这个方法的进程结束,主进程才会接着进行,但现在还没用到,先记得有这个方法,遇到再来看。

子进程(subprocess)

subprocess模块可以帮助我们生成一个新的进程,可以让我们在python中调用其他可执行的程序,比如在终端cd切换文件夹啥的。
subprocess提供了一些接口,能帮助我们对这个新的外部进程进行操作,这里学三种主要的。
subprocess.run():

subprocess.Popen():
这个方法就是能够实现和终端交互命令,具体怎么操作,以后再学。
subprocess.call()用的爬取B站视频有这个调用的,具体操作应该也是在shell里面进行命令传输,具体里面的参数,以后会慢慢学到。

进程间的通信

进程之间的通信,python在模块里提供了队列queue和Pipes来实现进程之间的通信。

import multiprocessing as mp

def job(q):
    res = 0
    for i in range(100):
        res = i*100
    q.put(res)

if __name__ == "__main__":
    q = mp.Queue#创建一个队列对象
    p1 = mp.Process(target=job,args=(q,))
    p2 = mp.Process(target=job,args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()#join()就记住,就是引用这个方法的进程结束的意思,join里面可以传入参数,就是这个进程运行的时间。
    res1 = q.get()
    res2 = q.get()
    print(res1+res2)

这个代码是在视频里看的比较容易懂,在Windows里不会报错,但是运行就会报错。

文档里面的代码也是比较容易看懂的。

多线程

进程是由若干线程组成的,一个进程至少有一个线程。
当我们启动当前程序,就是启动了一个进程,任何进程都会至少启动一个线程,这个线程叫做主线程,主线程可以启动新的线程,Python的threading模块有个current_thread()函数,这个函数永远返回当前线程的实例对象,所以可以这样threading.current_thread().name来打印线程实例对象的名字,主线程的名字叫做MainThread,我们在创建子线程的时候,除了跟创建进程那样需要传入要执行的任务函数,还多一个给线程命名的参数,比如这样:t = threading.Thread(target=loop, name='LoopThread')#这样就是新创建一个线程,这个线程的名字叫做LoopThread。

import time, threading

# 新线程执行的代码:
def loop():
    print('thread %s is running...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n = n + 1
        print('thread %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)#这一行是打印当前线程的名字
#这一行是创建了一个子线程,并命名。
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)

Lock

线程的调度是由操作系统决定的,所以当创建了多个子线程,这些线程交替执行,顺序我们不知道。
跟进程不同的是,在进程中,会对同一个变量进行拷贝,然后放进进程里,不会影响其他进程对这个变量的操作;但是在多线程里,同一个变量会被任何线程给修改。

这是一个多线程的代码,对于这个变量balance,chang_it()函数里只是加一下减一下,最后结果还是0,但是当使用多线程后,多线程的执行是这样的:

对于这个change_it()函数,多个线程交替执行,所以最后结果不一样。所以需要Lock来对这个函数上锁,这样就不会就只会单个线程执行这一段,记得上锁之后必须要释放锁,所以要用try-finally来写

lock.acquire()获取锁;lock.release()释放锁。

GIL锁:Global Interpreter Lock

以后再补充

Threadlocal

一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。
以后再补充。

后面还有需要再补充的,等需要的时候再来补充。

正则表达式

正则表达式是用来匹配字符串的。比如用来判断一串e-mail字符是否规范。用法就是:一、创建一个用来匹配正则表达式,二、去判断输入的是否规范。可以和之前遇到的通配符一起学一下。
\d 匹配数字 、 \w匹配字母或数字 \s 表示空白字符,空格,制表符等 就像这样
00\d 007; 00\w 00A

  1. .可以匹配任意字符
  2. *表示任意个字符(包括0个)
  3. +表示至少一个字符
  4. ?表示0个或1个字符
  5. {n}表示n个字符,用{n,m}表示n-m个字符
  6. ''转义(具体咋用,就是_这样,知道就行。)

进阶

可以用[]表示范围,精确地匹配

  1. [0-9a-zA-Z_]可以匹配一个数字、字母或者下划线;(前面是数字0到9,所以第一个数字,后面是a到z和A到Z,所以字母,然后加一个转义的下划线_);
  2. [0-9a-zA-Z_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z','Py3000'等等;
  3. [a-zA-Z_][0-9a-zA-Z_]*可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的变量;
  4. [a-zA-Z_][0-9a-zA-Z_]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。
  5. A|B可以匹配A或B,所以(P|p)ython可以匹配'Python'或者'python'
  6. 表示行的开头,\d表示必须以数字开头。
  7. $表示行的结束,\d$表示必须以数字结束。

re模块

由于\本身就有转义的意思,所以为了表示\就用两个\表示,就这样"abc\ABC"来表示"abc\ABC"。但最好还是这样写,在前面加个前缀r,这样r“abc\ABC”。
引入re模块,来进行匹配的判断。

如果匹配成功就会返回match类型的对象,如果匹配失败就会返回None。

切分字符串


正常使用切片的split不能一下子切分多个连续的,所以可以使用正则表达式里面的切片操作。
用法就是引入re模块的split方法,主要,需要以什么分割就写个r"[]"然后再加上要分割的字符串。

分组

m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
m.group(0)
m.group(1)
m.group(2)

当匹配一个对象后,可以使用group()方法来返回子串,group(0)永远返回的是整个字符串。匹配的对象使用groups()对象,就会返回这个字符串。

贪婪匹配


这个就是加了?号的,这个?号就是前面遇到的通配符。

编译

可以使用re.compile(r'^(\d{3})-(\d{3,8})$')来定义一个正则表达式的字符串,这样返回一个Regular Expression对象,下次可以直接用这个对象来匹配字符串。

正则表达式其实还有很多很多东西需要去学习,文档列的就这些,以后用到再去学。

接着后面就是常用的内置模块和第三方模块。

标签:__,进阶,Python,创建,print,线程,进程,name
From: https://www.cnblogs.com/huanc/p/17441379.html

相关文章

  • Python进阶七
    访问数据库importsqlite3#连接一个数据库,要是没有就会自己创建一个conn=sqlite3.connect("MySQL.db")#创建一个游标,用于执行SQL语句cursor=conn.cursor()##创建表创建表的一般结构就是:createtable<表名>(<属性名字类型>,......);#或者也可以把要执行的语......
  • python中测试方法所用的时间—timeit
    方法代码使用timeit方法测试两个函数的运行速度importtimeitstrlist=['Thisisalongstringthatwillnitkeepinmemory.'forninrange(10000)]defuse_join():#使用字符串的join方法连接多个字符串return''.join(strlist)defues_plus():#使用运算符+连接多个字......
  • python使用hTTP方法
    Python中可以使用requests库来发送HTTP请求,其中包括GET、POST、PUT、DELETE等方法。下面是一个使用requests库发送HTTP请求的示例:importrequests#发送GET请求response=requests.get('ExampleDomain')#发送POST请求data={'key1':'value1','key2':'val......
  • python 实现google authenticator 认证
    importosimporttracebackimportpyotpfromqrcodeimportQRCode,constantsclassGoogleAuthenticatorClient:def__init__(self,secret_key=None):self.secret_key=secret_keydefcreate_secret(self):"""生......
  • python 读取、写入、追加、覆盖xls文件
    python读取、写入、追加、覆盖xls文件0、写在前面测试源xls是这样的1、读取xlsdefread_xls(filename:str,sheet_name:str)->List[list]:filename=os.path.abspath(filename)assertos.path.isfile(filename),f'{filename}isnotfile'assertfilen......
  • Python使用to_csv导出文件时参数注意事项
    使用to_csv导出文件时,一定要指定index参数和encoding参数这两个参数;index参数:默认为True,会添加一列标记数据索引。encoding参数:如果不指定utf_8_sig,使用默认参数值,则导出的文件可能会有乱码或串列。cake_data.to_csv(r"C:\E\data.csv",index=False,encoding='utf_8_sig')......
  • Python中的Union这个类的使用
    在Python中,Union是typing模块中定义的一个类,用于表示多个类型中的任意一种类型。Union类型可以用于表示参数或函数返回值等多种情况下可能的不同类型。具体而言,Union类型可以使用typing.Union[type1,type2,...]的语法来定义,其中type1、type2等参数为可能的类型。例......
  • Python——基于数据挖掘的上市公司财务造假识别(制造业)
    制造业importpandasaspdimportnumpyasnp%matplotlibinlineimportmatplotlib.pyplotaspltimportseabornassnscolor=sns.color_palette()fromscipyimportstatsfromscipy.statsimportnorm,skewt1=pd.read_csv("制造业.csv")t1_train=t1.d......
  • Python工具箱系列(三十四)
    SQLAlchemy是著名的ORM(ObjectRelationalMapping-对象关系映射)框架。其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。对许多语言(例如JAVA/PYTHON)来说就是定义一个对象,并且这个对象对应着一张数据库的表。而这个对象的实例,就对应着表中的一条记录。其整体思......
  • python:yaml模块
    python:yaml模块https://www.jianshu.com/p/eaa1bf01b3a6https://www.runoob.com/w3cnote/yaml-intro.html......