系统编程

进程线程对比

1、根本区别

 进程是操作系统资源分配的基本单位;而线程是任务调度和执行的基本单位。
 每个进程都有独立的代码和数据空间;同一类线程共享代码和数据空间。
 在操作系统中能同时运行多个进程(程序);而在同一个进程中有多个线程同时执行。
 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。
 包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的线程共同完成的。

2、优缺点

线程执行开销小,但不利于资源的管理和保护,而进程正相反。

进程

1、进程VS程序

编写完毕的代码,在没有运行的时候,称为程序。
正在运行着的代码,称为进程。
进程除了包含代码之外还要有代码的运行环境。

2、fork()

python的os模块封装了常见的系统相关,其中就包括fork(Windows不支持),可以在python程序中轻松创建子进程。

import os
pid = os.fork()

os.fork()方法执行一次会返回两次,操作系统自动把当前进程(父进程)复制一份(子进程),然后在父进程和子进程内分别执行。

# ubuntu os.fork()方法开辟进程(复制主进程数据,将数据传入子进程)

os.fork()
print("process")
# process
# process

# 子进程返回值为0,父进程返回子进程的进程id
# getpid() 获取当前进程id,getppid()获取父进程id
# 子进程可以创建子进程
# 父子进程的执行没有先后顺序
# 在多个进程中每个进程都复制父进程的所有数据,互不影响

pid = os.fork()
print("main  pid %d parent pid %d" % (os.getpid(), os.getppid()))
if pid == 0:
    print("child1  pid %d parent pid %d" % (os.getpid(), os.getppid()))
    pid2 = os.fork()
    if pid2 == 0:
        print("child2  pid %d parent pid %d" % (os.getpid(), os.getppid()))
    else:
        print("child1  pid %d parent pid %d" % (os.getpid(), os.getppid()))
else:
    print("main pid %d" % (os.getpid()))

3、multiprocessing模块

"""
Process生成进程实例
target指明进程入口函数
p1.pid得到进程的id
进程函数执行完毕进程执行完毕释放资源
主进程结束后会结束开启的子进程
join()方法会阻塞进程(join方法在哪个进程写就阻塞哪个进程)
terminate():终止进程
is_alive():判断进程是否结束
"""

from multiprocessing import Process
import os,time


# p1 进程入口函数
def p1process():
    while True:
        time.sleep(1)
        print("进程p1执行了")


def p2process():
    while True:
        time.sleep(1)
        print("进程p2执行了")


def main():
    # 1 创建进程:创建Process类的实例
    # 2 通过target指定进程入口函数
    p1 = Process(target=p1process)
    # 3 开启进程
    p1.start()
    # 阻塞主进程,此时p2不会执行,把p1中的循环去掉就可以执行p2了
    p1.join()
    p2 = Process(target=p2process, name="pp1")
    p2.start()

    # 终止进程
    p1.terminate()

    print(p1.is_alive(), p2.is_alive())


4、进程传参

"""
进程之间传参
一个进程修改不会影响其他进程
提供元素参数 args和字典参数kwargs
"""

from multiprocessing import Process
import time


def processmain(pam1, **kwargs):
    print("++", pam1)
    # ++ [1]
    pam1.append(2)
    print(pam1, kwargs)
    # [1, 2] {'name': 'liuhaoran'}


def main():
    list1 = [1]
    p1 = Process(target=processmain, args=(list1, ), kwargs={"name": "liuhaoran"})
    p1.start()
    time.sleep(1)
    p1.join()
    print(list1)
    # [1]


if __name__ == "__main__":
    main()

5、进程封装

"""
当调用进程对象的start方法会执行进程的run方法,
如果在进程子类重写run方法
此时自定义的入口函数就不会执行了
run方法才是真正的入口函数
"""

from multiprocessing import Process


def mainprocess():
    print("自定义入口函数")


class MyProcess(Process):

    # def __init__(self):
    #     Process.__init__(self)

    def run(self):
        print("执行了")


def main():
    p1 = MyProcess(target=mainprocess)
    p1.start()


if __name__ == "__main__":
    main()

6、进程池Pool

初始化进程池时需要给定最大进程数,当请求Pool时会根据当前池子中获取进程,如果有可用进程则执行,如果没有可用进程则等待,直到有可用进程。

from multiprocessing import Pool
import os
import time
# print(os.cpu_count())
# 4


# 创建入口函数
def process(i):
    while True:
        time.sleep(2)
        print("pid:", os.getpid(), "ppid:", os.getppid())
        print(i)


if __name__ == "__main__":
    print("pid", os.getpid(), "ppid", os.getppid())
    # 构造一个进程池
    pool = Pool(4)
    for i in range(20):
        # 异步调用不阻塞主进程
        pool.apply_async(process, args=(i,))

    # 关闭进程池,不再接受新的任务
    pool.close()

    # 不关任务是否完成,立即终止
    time.sleep(5)
    print("进程已经开启了5秒,即将终止")
    pool.terminate()
    # pool.apply_async(process)
    # ValueError: Pool not running

    # 阻塞主进程,等待子进程的退出,必须在close或terminate之后使用
    pool.join()
    print("finish")

7、Queue进程间通信

(1)Queue用法

from multiprocessing import Queue

q = Queue(5,)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
q.put(5)
print(q.qsize())
try:
    # 阻塞3秒后强行放入数据,此时引发错误
    q.put(6, block=True, timeout=3)
    # 不阻塞进程,强行放入数据
    q.put(6, block=False)
    # 或者使用put_nowait()方法
    q.put_nowait(6)
except Exception as e:
    print("error")

q.get()
q.get()
q.get()
q.get()
q.get()
try:
    q.get(block=True, timeout=2)
    q.get(block=False)
    q.get_nowait()
except Exception as e:
    print("get error")

(2)使用Queue共享数据

"""
使用队列在进程间共享数据
"""
from multiprocessing import Queue, Process
import time


# 获取任务写入队列
def pwrite(taskqueue):
    for i in range(10):
        time.sleep(2)
        taskqueue.put(i)
        # print(taskqueue.qsize())


# 从队列读取任务
def pread(taskqueue):
    while True:
        # get取不到任务会阻塞读进程
        task = taskqueue.get()
        print("读取到任务", task)


if __name__ == "__main__":
    # 构建10个任务队列
    taskQueue = Queue(10)

    pw = Process(target=pwrite, args=(taskQueue,))
    pw.start()
    print("写进程开启 pid", pw.pid)

    pr = Process(target=pread, args=(taskQueue,))
    pr.start()
    print("读进程开启 pid", pr.pid)

    pw.join()
    pr.join()
    print("finish")

(3)进程池下共享Queue

from multiprocessing import Pool, Manager
import time


def read(q):
    while True:
        r = q.get()
        print(r)
        time.sleep(0.1)


def write(q):
    for i in range(5):
        q.put(i)
        time.sleep(2)


if __name__ == "__main__":
    q = Manager().Queue(5)
    q.put(-2)
    q.put(-1)
    pool = Pool(5)

    pool.apply_async(write, (q,))
    pool.apply_async(read, (q,))
    pool.close()
    pool.join()
    print("finish")

多线程-threading

1、使用threading模块

多线程并发花费时间较短,创建好的线程需要start()启动。

from threading import Thread
import time


def prt():
    print("hello world")
    time.sleep(1)


def timecount(f):
    def tc():
        start = time.time()
        f()
        end = time.time()
        print(end - start)
    return tc


@timecount
def threadmain():
    list1 = []
    for i in range(5):
        i = Thread(target=prt)
        i.start()
        list1.append(i)

    print(list1)
    for l in list1:
        l.join()


@timecount
def main():
    for i in range(5):
        prt()


if __name__ == "__main__":
    # main()
    threadmain()

2、获取线程数

import threading
import time


def fun():
    time.sleep(1)
    print("hello")


if __name__ == "__main__":
    t = threading.Thread(target=fun)
    t.start()
    while True:
        print(threading.enumerate())
        time.sleep(0.2)

3、threading封装

import threading


class MyThread(threading.Thread):
    def run(self):
        print("hello world")


if __name__ == "__main__":
    t = MyThread()
    t.start()

4、threading共享全局变量

一个进程内的线程直接可以共享全局变量

import threading
num = 1


def fun1():
    num = 2
    print(num) # 2

fun1()
print(num) # 1


def fun2():
    global num
    num = 3
    print(num) # 3

fun2()
print(num) # 3


def fun3():
    global num
    num = 4
    print(num) # 4


if __name__ == "__main__":
    t = threading.Thread(target=fun3)
    t.start()
    print(num) # 4

多个线程的同时操作共享变量会造成数据混乱

5、互斥锁

当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
(1)互斥锁状态

# create
lock1 = threading.Lock()
# lock
lock1.acquire()
# release
lock1.release()

(2)使用互斥锁

import threading
import time
num = 0


def fun1():
    global num
    for i in range(100000):
        lock1.acquire()
        num += 1
        lock1.release()


def fun2():
    global num
    for r in range(100000):
        lock1.acquire()
        num += 1
        lock1.release()


if __name__ == "__main__":
    lock1 = threading.Lock()
    t1 = threading.Thread(target=fun1)
    t1.start()
    t2 = threading.Thread(target=fun2)
    t2.start()

    time.sleep(2)
    print(num)

优点:
 确保了某段关键代码只能由一个线程从头到尾完整的执行。
缺点:
 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁。

(3)死锁

import threading
import time


def fun1():
    if lock1.acquire():
        # print("fun1")
        time.sleep(2)
        if lock2.acquire():
            print("finish")


def fun2():
    if lock2.acquire():
        # print("fun2")
        time.sleep(2)
        if lock1.acquire():
            print("finish")


if __name__ == "__main__":
    lock1 = threading.Lock()
    lock2 = threading.Lock()

    t1 = threading.Thread(target=fun1)
    t2 = threading.Thread(target=fun2)
    t1.start()
    t2.start()

(4)TheadLocal

"""
ThreadLocal是全局变量,每个线程都只能读写自己线程的独立副本,互不干扰
"""
import threading


def thread():
    tlocal.age = 22
    print(tlocal.age)


if __name__ == "__main__":
    tlocal = threading.local()
    tlocal.name = "liuhaoran"
    print(tlocal.name)

    t1 = threading.Thread(target=thread)
    t1.start()
    t1.join()
    print(tlocal.age)
# AttributeError: '_thread._local' object has no attribute 'age'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值