【python】基础知识巩固(十)

目录

🚩进程和线程的概念

🏴‍☠️补充:

🏴‍☠️区别:

🚩多进程

🏴‍☠️multiprocessing

 🏴‍☠️代码解读

1)join()方法

2)start()方法

3)Process([group [, target [, name [, args [, kwargs]]]]])

4)getpid

 🚩Pool进程池

 🏴‍☠️代码解读:

1.apply_async(func[, args[, kwds[, callback[, error_callback]]]])

2)注意

🚩子进程 

 🚩进程间通信

🚩多线程 

🏴‍☠️分类:

例如:

🏴‍☠️线程与进程的区别 

代码说明:

问题解决: 


🚩进程和线程的概念

进程是资源分配的基本单位,它是程序执行时的一个实例

在程序运行时创建;线程程序执行的最小单位,是进程的一个执行流

简单来说线程是进程中的一部分,进程包含多个线程在运行

🏴‍☠️补充:

一个线程由多个协程组成的

🏴‍☠️区别:

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。

🚩多进程

python内置os模块,让Python程序中轻松创建子进程

🏴‍☠️multiprocessing

由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块,不管window还是mac,unix都可用

例如:启动一个子进程并等待其结束:

from multiprocessing import Process
import os

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

if __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.')

 output:

 🏴‍☠️代码解读

1)join()方法

当一个线程操作需要等待另一个线程执行完毕之后才能继续进行时,使用Join()方法。Join方法会等到使用该方法的线程结束后再执行下面的代码

2)start()方法

开始线程

3)Process([group [, target [, name [, args [, kwargs]]]]])

注意:1. 必须使用关键字方式来指定参数;

2. args指定的为传给target函数的位置参数,是一个元祖形式,必须有逗号

1.group应该是None;为将来ThreadGroup实现类时的扩展保留 。

2.targetrun()方法要调用的可调用对象。默认为None,意味着什么都不调用。

3.name是线程名称。默认情况下,唯一名称的构造形式为“Thread- N ”,其中N是小十进制数,或者“Thread- N (target)”,其中“target”是指定target.__name__了 目标参数的情况。

4.args是目标调用的参数元组。默认为().

5.kwargs是目标调用的关键字参数字典。默认为{}.

6.如果不是None守护进程显式设置线程是否是守护进程。如果None(默认),守护进程属性是从当前线程继承的。

4)getpid

返回进程ID。在进程产生之前,这将是 None.

 🚩Pool进程池

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

 🏴‍☠️代码解读:

1.apply_async(func[, args[, kwds[, callback[, error_callback]]]])

apply() 方法的一个变种,返回一个 AsyncResult 对象。

如果指定了 callback , 它必须是一个接受单个参数的可调用对象。

当执行成功时, callback 会被用于处理执行后的返回结果,否则,调用 error_callback 。

如果指定了 error_callback , 它必须是一个接受单个参数的可调用对象。当目标函数执行失败时, 会将抛出的异常对象作为参数传递给 error_callback 执行。

回调函数应该立即执行完成,否则会阻塞负责处理结果的线程。


2)注意

调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process

🚩子进程 

subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出

""" 
CSDN : heart_6662
PYTHON amateur   
"""
import subprocess

print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)

 output:

 🚩进程间通信

Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

Queue为例,在父进程中创建两个子进程一个往Queue里写数据,一个从Queue里读数据:

from multiprocessing import Process, Queue
import os, time, random

# 写数据进程执行的代码:
def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        q.put(value)
        time.sleep(random.random())

# 读数据进程执行的代码:
def read(q):
    print('Process to read: %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()
    # 启动子进程pr,读取:
    pr.start()
    # 等待pw结束:
    pw.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    pr.terminate()

 

🚩多线程 

多任务可以由多进程完成,也可以由一个进程内的多线程完成

很多高级语言都内置线程,而Python的线程是真正的Posix Thread,而不是模拟出来的线程

🏴‍☠️分类:

_threadthreading_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。

例如:

启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行

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)

 

🏴‍☠️线程与进程的区别 

                                                          就是内容共享问题

 多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,

多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱

例如: 

import time, threading

# 假定这是你的银行存款:
balance = 0

def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(2000000):
        change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

代码说明:

定义了一个共享变量balance,初始值为0,并且启动两个线程,先存后取,理论上结果应该为0 

                                                                可结果为-3

原因:

因为高级语言的一条语句在CPU执行时是若干条语句,即使一个简单的计算;例如

balance = balance + n

也分两步:

  1. 计算balance + n,存入临时变量中;
  2. 将临时变量的值赋给balance
x = balance + n
balance = x

 

问题解决: 

                                                                   核心在于限制

如果我们要确保balance计算正确,就要给change_it()上一把锁,当某个线程开始执行change_it()时,该线程因为获得了锁,因此其他线程不能同时执行change_it(),直到锁被释放后,获得该锁以后才能改。

由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。

                           创建一个锁就是通过threading.Lock()来实现将代码加上我们的锁:

""" 
CSDN : heart_6662
PYTHON amateur   
"""
import time, threading

# 假定这是你的银行存款:
balance = 0

def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n


balance = 0
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

不管怎么运行,你的结果这次一次为0

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heart_6662

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值