python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器

简介: python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器

一、python线程死锁与递归锁

死锁现象

1

2

3

所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程

代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

from threading import Thread,Lock

import time

 

mutexA = Lock()

mutexB = Lock()

 

class MyThread(Thread):

    def run(self):

        self.task1()

        self.task2()

 

 

    def task1(self):

        mutexA.acquire()

        print('%s task1 get A' %self.name)

 

        mutexB.acquire()

        print('%s task1 get B' % self.name)

        mutexB.release()

 

        mutexA.release()

 

    def task2(self):

        mutexB.acquire()

        print('%s task2 get B' % self.name)

        time.sleep(1)  # Thread-2 拿到执行权,执行get A出现死锁,此时thread2需要B锁,而thread1占用,与此同时,thread1需要A锁,thread2占用

        mutexA.acquire()

        print('%s task2 get A' % self.name)

 

        mutexA.release()

        mutexB.release()

 

 

if __name__ == '__main__':

    for in range(10):

        t = MyThread()

        t.start()

输出结果:

1

2

3

4

Thread-1 task1 get A

Thread-1 task1 get B

Thread-1 task2 get B

Thread-2 task1 get A # 出现死锁,整个程序被阻塞

2.递归锁

1

2

3

4

5

解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

 

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。

 

直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁,二者的区别是:递归锁可以连续acquire多次,而互斥锁只能acquire一次

代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

from threading import Thread,RLock

import time

 

mutexA = mutexB = RLock()

 

class MyThread(Thread):

    def run(self):

        self.task1()

        self.task2()

 

 

    def task1(self):

        mutexA.acquire()

        print('%s task1 get A' %self.name)

 

        mutexB.acquire()

        print('%s task1 get B' % self.name)

        mutexB.release()

 

        mutexA.release()

        time.sleep(1) # Thread-2 拿到执行权,,此时counter=0,thread2执行task1

 

    def task2(self):

        mutexB.acquire()

        print('%s task2 get B' % self.name)

 

        mutexA.acquire()

        print('%s task2 get A' % self.name)

 

        mutexA.release()

        mutexB.release()

 

 

if __name__ == '__main__':

    for in range(10):

        t = MyThread()

        t.start() 

输出结果:

1

2

3

4

5

6

7

8

9

10

11

12

Thread-1 task1 get A

Thread-1 task1 get B

Thread-2 task1 get A

Thread-2 task1 get B

Thread-3 task1 get A

Thread-3 task1 get B

Thread-4 task1 get A

Thread-4 task1 get B

Thread-5 task1 get A

Thread-5 task1 get B

Thread-6 task1 get A

......

二、信号量

1.什么是信号量

1

2

3

4

5

信号量也是一种锁。

 

信号量的主要用途是用来控制线程的并发量的,Semaphore管理一个内置的计数器,每调用一次acquire()方法时,计数器-1,每调用一次release()方法时,内部计数器+1。

 

不过需要注意的是,Semaphore内部的计数器不能小于0!当它内部的计数器等于0的时候,这个线程会被锁定,进入阻塞状态,直到其他线程去调用release方法。

2.用处

1

信号量`semaphore` 是用于控制进入数量的锁。有哪些应用场景呢,比如说在读写文件的时候,一般只能只有一个线程在写,而读可以有多个线程同时进行,如果需要限制同时读文件的线程个数,这时候就可以用到信号量了(如果用互斥锁,就是限制同一时刻只能有一个线程读取文件)。又比如在做爬虫的时候,有时候爬取速度太快了,会导致被网站禁止,所以这个时候就需要控制爬虫爬取网站的频率。

3.信号量使用的示例

semaphore内部维护了一个条件变量condition,构造函数是:

1

Semaphore(value=1) # value设置是内部维护的计数器的大小,默认为1.

主要有两个方法:

1

2

每当调用acquire()时,内置计数器-1,直到为0的时候阻塞

每当调用release()时,内置计数器+1,并让某个线程的acquire()从阻塞变为不阻塞

用爬虫来举例,假如说有一个UrlProducer线程,爬取url,多个htmlSpider线程,爬取url对应的网页。如果直接开20个htmlSpider线程,20个线程是同时执行的,现在要限制同时执行能执行三个,就可以使用信号量来控制: 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

import threading

import time

class htmlSpider(threading.Thread):

    def __init__(self, url, sem):

        super().__init__()

        self.url = url

        self.sem = sem

 

    def run(self):

        time.sleep(2)

        print("got html text success")

        self.sem.release() # 内部维护的计数器加1,并通知内部维护的conditon通知acquire

 

class UrlProducer(threading.Thread):

    def __init__(self, sem):

        super().__init__()

        self.sem = sem

 

    def run(self):

        for in range(20):

            self.sem.acquire() # 内部维护的计数器减1,到0就会阻塞

            html_thread = htmlSpider("http://baidu.com/{}".format(i), self.sem)

            html_thread.start()

 

if __name__ == "__main__":

    sem = threading.Semaphore(3) #设置同时最多3个

    url_producer = UrlProducer(sem)

    url_producer.start()

从结果可以看出,每次都几乎是三个同时的完成任务。

三、Event事件

1. 什么是事件

1

同进程的一样,线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行

2. Event几种方法

event.isSet() 返回event的状态值;
event.wait() 如果 event.isSet()==False将阻塞线程;
event.set() 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统度;
event.clear() 恢复event的状态值为False。

3.代码示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

from threading import Thread,Event

import time

 

event=Event()

 

def light():

    print('红灯正亮着')

    time.sleep(3)

    event.set() #绿灯亮

 

def car(name):

    print('车%s正在等绿灯' %name)

    event.wait() #等灯绿 此时event为False,直到event.set()将其值设置为True,才会继续运行.

    print('车%s通行' %name)

 

if __name__ == '__main__':

    # 红绿灯

    t1=Thread(target=light)

    t1.start()

    # 车

    for in range(10):

        t=Thread(target=car,args=(i,))

        t.start()

四、线程队列Queue

1. 队列分类

Queue 哪个数据先存入,取数据的时候先取哪个数据,同生活中的排队买东西
LifoQueue 哪个数据最后存入的,取数据的时候先取,同生活中手枪的弹夹,子弹最后放入的先打出
PriorityQueue 存入数据时候加入一个优先级,取数据的时候优先级最高的取出

2. Queue简介

1

线程队列Queue,也称FIFO,存在队列中的数据先进先出,就好比拉肚子,吃什么拉什么~~呃呃,有点重口味

Queue常用函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

Queue.qsize()    返回队列大小

 

Queue.empty()  判断队列是否为空

 

Queue.full()        判断队列是否满了

 

Queue.get([block[,timeout]])  从队列头删除并返回一个item,block默认为True,表示当队列为空却去get的时候会阻塞线程,等待直到有有item出现为止来get出这个item。如果是False的话表明当队列为空你却去get的时候,会引发异常。在block为True的情况下可以再设置timeout参数。表示当队列为空,get阻塞timeout指定的秒数之后还没有get到的话就引发Full异常。

 

Queue.task_done()  从场景上来说,处理完一个get出来的item之后,调用task_done将向队列发出一个信号,表示本任务已经完成(与Queue.get配对使用)。

 

Queue.put(…[,block[,timeout]])  向队尾插入一个item,同样若block=True的话队列满时就阻塞等待有空位出来再put,block=False时引发异常。同get的timeout,put的timeout是在block为True的时候进行超时设置的参数。

 

Queue.join()  监视所有item并阻塞主线程,直到所有item都调用了task_done之后主线程才继续向下执行。这么做的好处在于,假如一个线程开始处理最后一个任务,它从任务队列中拿走最后一个任务,此时任务队列就空了但最后那个线程还没处理完。当调用了join之后,主线程就不会因为队列空了而擅自结束,而是等待最后那个线程处理完成了。

Queue使用:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

# !usr/bin/env python

# -*- coding:utf-8 _*-

 

import threading

import queue

 

q = queue.Queue(5)  # 长度,队列中最多存放5个数据

 

 

def put():

    for in range(20):

        q.put(i)

        print("数字%d存入队列成功" % i)

    q.join()  # 阻塞进程,直到所有任务完成,取多少次数据task_done多少次才行,否则最后的ok无法打印

    print('ok')

 

 

def get():

    for in range(20):

        value = q.get()

        print("数字%d重队列中取出" % value)

        q.task_done()  # 必须每取走一个数据,发一个信号给join

    # q.task_done()   #放在这没用,因为join实际上是一个计数器,put了多少个数据,

    # 计数器就是多少,每task_done一次,计数器减1,直到为0才继续执行

 

 

t1 = threading.Thread(target=put, args=())

t1.start()

t2 = threading.Thread(target=get, args=())

t2.start()

输出结果:

1

2

3

4

5

6

7

8

9

10

11

数字0存入队列成功

数字1存入队列成功

数字2存入队列成功

数字3存入队列成功

数字4存入队列成功

数字0重队列中取出

数字1重队列中取出

数字2重队列中取出

数字3重队列中取出

数字4重队列中取出

......

3. LifoQueue简介

1

与Queue相反,最后存入的数据最先取出,最先存入的数据最后取出,如果说FIFO是吃什么拉什么,那么LIFO就是吃什么吐什么,先吃的后吐,后吃的先吐~~真是重口味呀!

LifoQueue函数介绍:

1

函数不做过多介绍了,已经在 python线程队列Queue-FIFO 有了详细讲解,两者都属于Queue,函数都一样!

LifoQueue使用: 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

# !usr/bin/env python

# -*- coding:utf-8 _*-

 

import queue

import threading

import time

 

# 可以设置队列的长度 q=queue.LifoQueue(5),意味着队列中最多存放5个元素,当队列满的时候自动进入阻塞状态

q=queue.LifoQueue()

def put():

    for in range(10):

        q.put(i)

        print("数据%d被存入到队列中" % i)

    q.join()

    print('ok')

 

def get():

    for in range(10):

        value = q.get()

        print("数据%d从队列中取出" % value)

        q.task_done()

 

t1=threading.Thread(target=put,args=())

t1.start()

t2=threading.Thread(target=get,args=())

t2.start()

输出结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

数据0被存入到队列中

数据1被存入到队列中

数据2被存入到队列中

数据3被存入到队列中

数据4被存入到队列中

数据5被存入到队列中

数据6被存入到队列中

数据7被存入到队列中

数据8被存入到队列中

数据9被存入到队列中

数据9从队列中取出

数据8从队列中取出

数据7从队列中取出

数据6从队列中取出

数据5从队列中取出

数据4从队列中取出

数据3从队列中取出

数据2从队列中取出

数据1从队列中取出

数据0从队列中取出

ok

4. PriorityQueue简介

1

在数据存入的时候设置优先级,设置的值越小,优先级越高,取数据的时候默认按照优先级最高的取出

PriorityQueue函数介绍:

1

函数不做过多介绍了,已经在 python线程队列Queue-FIFO 有了详细讲解,两者都属于Queue,函数都一样!

PriorityQueue使用:

1

按优先级:不管是数字、字母、列表、元组等(字典、集合没测),使用优先级存数据取数据,队列中的数据必须是同一类型,都是按照实际数据的ascii码表的顺序进行优先级匹配,汉字是按照unicode表。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

# !usr/bin/env python

# -*- coding:utf-8 _*-

 

import queue

import threading

import time

 

q = queue.PriorityQueue()

q.put([1, 'ace'])

q.put([40, 333])

q.put([3, 'afd'])

q.put([5, '4asdg'])

# 1是级别最高的,

while not q.empty():  # 不为空时候执行

    print(q.get())

 

 

 

q = queue.PriorityQueue()

q.put('我')

q.put('你')

q.put('他')

q.put('她')

q.put('ta')

while not q.empty():

    print(q.get())  

运行结果:  

1

2

3

4

5

6

7

8

9

[1, 'ace']

[3, 'afd']

[5, '4asdg']

[40, 333]

ta

五、Python进程池、线程池、回调函数

1. 池的概念

1

2

3

不管是线程还是进程,都不能无限制的开下去,总会消耗和占用资源。

 

也就是说,硬件的承载能力是有限度的,在保证高效率工作的同时应该还需要保证硬件的资源占用情况,所以需要给硬件设置一个上限来减轻硬件的压力,所以就有了池的概念。

2. 进程池与线程池的使用方法(除了使用模块不一样外其他都相同)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

from concurrent.futures import ProcessPoolExecutor  # 导入进程池模块

from concurrent.futures import ThreadPoolExecutor # 导入线程池模块

import os

import time

import random

 

# 下面以进程池为例,线程池只是使用导入模块不一样,仅此而已。

def task(name):

    print('name:[%s]|进程:[%s]正在运行' % (name, os.getpid()))

    time.sleep(random.randint(1, 3))   # 模拟进程运行耗费时间。

 

# 这一步的必要性:在创建进程时,会将代码以模块的方式从头到尾导入加载执行一遍

# (所以创建线程如果不写在main里面的话,这个py文件里面的所有代码都会从头到尾加载执行一遍

# 就会导致在创建进程的时候产生死循环。)

if __name__ == '__main__':

    pool = ProcessPoolExecutor(4)  # 设置线程池的大小,默认等于cpu的核心数。

    for in range(10):

        pool.submit(task, '进程%s' % i)  # 异步提交(提交后不等待)

    

    pool.shutdown(wait=True)  # 关闭进程池入口不再提交,同时等待进程池全部运行完毕。(类似join方法,但是shutdown等待全部线程结束后在执行主进程,默认wait等于true

    print('主') # 标识一下主进程的完毕之前的语句   

运行结果:

name:[进程0]|进程:[17656]正在运行
name:[进程1]|进程:[14380]正在运行
name:[进程2]|进程:[18956]正在运行
name:[进程3]|进程:[3564]正在运行
name:[进程4]|进程:[14380]正在运行
name:[进程5]|进程:[18956]正在运行
name:[进程6]|进程:[3564]正在运行
name:[进程7]|进程:[18956]正在运行
name:[进程8]|进程:[3564]正在运行
name:[进程9]|进程:[17656]正在运行

3.同步调用:提交任务,原地等待该任务执行完毕,拿到结果后再执行下一个任务,导致程序串行执行!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

from concurrent.futures import ProcessPoolExecutor  # 导入进程池模块

from concurrent.futures import ThreadPoolExecutor # 导入线程池模块

import os

import time

import random

 

 

def task(name):

    print('name:[%s]|进程[%s]正在运行...' % (name, os.getpid()))

    time.sleep(random.randint(1, 3))

    return '拿到[%s]|进程%s的结果...' % (name, os.getpid())

 

if __name__ == '__main__':

    pool = ProcessPoolExecutor(4)

    result = []  # 创建一个空列表来搜集执行结果

    for in range(10):

        res = pool.submit(task, '进程%s' % i).result()  # 使用.result()方法得到每次的结果,同步调用

        result.append(res)

    pool.shutdown(wait=True)

    for in result:

        print(j)

    print('主进程')  

运行结果:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

name:[进程0]|进程[3376]正在运行...

name:[进程1]|进程[27124]正在运行...

name:[进程2]|进程[10176]正在运行...

name:[进程3]|进程[28636]正在运行...

name:[进程4]|进程[3376]正在运行...

name:[进程5]|进程[27124]正在运行...

name:[进程6]|进程[10176]正在运行...

name:[进程7]|进程[28636]正在运行...

name:[进程8]|进程[3376]正在运行...

name:[进程9]|进程[27124]正在运行...

拿到[进程0]|进程3376的结果...

拿到[进程1]|进程27124的结果...

拿到[进程2]|进程10176的结果...

拿到[进程3]|进程28636的结果...

拿到[进程4]|进程3376的结果...

拿到[进程5]|进程27124的结果...

拿到[进程6]|进程10176的结果...

拿到[进程7]|进程28636的结果...

拿到[进程8]|进程3376的结果...

拿到[进程9]|进程27124的结果...

主进程

异步调用:提交任务,不去等结果,继续执行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

from concurrent.futures import ProcessPoolExecutor

import os

import random

import time

 

def task(name):

    time.sleep(random.randint(1, 3))

    print('name: %s 进程[%s]运行...' % (name, os.getpid()))

 

 

if __name__ == '__main__':

    pool = ProcessPoolExecutor(4)

    for in range(10):

        pool.submit(task, '进程%s' % i)   # 异步调用,提交后不等待结果,继续执行代码

 

    pool.shutdown(wait=True)

    print('主进程')  

运行结果:

1

2

3

4

5

6

7

8

9

10

11

name: 进程3 进程[10016]运行...

name: 进程0 进程[12736]运行...

name: 进程1 进程[4488]运行...

name: 进程2 进程[3920]运行...

name: 进程5 进程[12736]运行...

name: 进程6 进程[4488]运行...

name: 进程4 进程[10016]运行...

name: 进程9 进程[4488]运行...

name: 进程8 进程[12736]运行...

name: 进程7 进程[3920]运行...

主进程

六、回调函数

1.什么是回调函数

1

2

3

上面我们在演示异步调用时候,说过提交任务不等待执行结果,继续往下执行代码,那么,执行的结果我们怎么得到呢?

 

可以为进程池和线程池内的每个进程或线程绑定一个函数,该函数在进程或线程的任务执行完毕后自动触发并接收任务的返回值当做参数,这个函数就是回调函数。

代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

from concurrent.futures import ThreadPoolExecutor

import time

import random

import requests

 

 

def task(url):

    print('获取网站[%s]信息' % url)

    response = requests.get(url)  # 下载页面

    time.sleep(random.randint(1, 3))

    return {'url': url, 'content': response.text}  # 返回结果:页面地址和页面内容

 

futures = []

def back(res):

    res = res.result()  # 取到提交任务的结果(回调函数固定写法)

    res = '网站[%s]内容长度:%s' % (res.get('url'), len(res.get('content')))

    futures.append(res)

    return futures

 

if __name__ == '__main__':

    urls = [

        'http://www.baidu.com',

        'http://www.dgtle.com/',

        'https://www.bilibili.com/'

    ]

    pool = ThreadPoolExecutor(4)

    futures = []

    for in urls:

        pool.submit(task, i).add_done_callback(back)  # 执行完线程后,使用回调函数

 

    pool.shutdown(wait=True)

    for in futures:

        print(j)

运行结果:

1

2

3

4

5

6

获取网站[http://www.baidu.com]信息

获取网站[http://www.dgtle.com/]信息

获取网站[https://www.bilibili.com/]信息

网站[http://www.dgtle.com/]内容长度:39360

网站[https://www.bilibili.com/]内容长度:69377

网站[http://www.baidu.com]内容长度:2381

七、定时器

Timer(定时器)是Thread的派生类,用于在指定时间后调用一个方法。

构造方法:Timer(interval, function, args=[], kwargs={})

1

2

3

interval: 指定的延迟时间

function: 要执行的方法

args/kwargs: 方法的参数

代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

import time

from threading import Timer

 

 

def task(name):

    print("%s 大帅比"%name)

 

if __name__ == '__main__':

    t = Timer(2,task,kwargs={"name":"lqz"})  #2表示间隔的时间

    t.start()   #正常情况下会延迟两秒后执行task函数

    time.sleep(1)

    t.cancel()  #如果Timer没有结束就会被停止执行

以上内容抄自于:

1

2

3

4

https://www.jianshu.com/p/58ec3e7a1edb

https://www.cnblogs.com/shuopython/p/11986089.html

https://www.cnblogs.com/zhangshengxiang/p/9606133.html

https://blog.csdn.net/qq_42992919/article/details/98201031

相关文章
|
18天前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
在数字世界的底层,操作系统扮演着不可或缺的角色。它如同一位高效的管家,协调和控制着计算机硬件与软件资源。本文将拨开迷雾,深入探索操作系统中两个核心概念——进程与线程。我们将从它们的诞生谈起,逐步剖析它们的本质、区别以及如何影响我们日常使用的应用程序性能。通过简单的比喻,我们将理解这些看似抽象的概念,并学会如何在编程实践中高效利用进程与线程。准备好跟随我一起,揭开操作系统的神秘面纱,让我们的代码运行得更加流畅吧!
|
2月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第16天】进程、线程和协程是计算机程序执行的三种基本形式。进程是操作系统资源分配和调度的基本单位,具有独立的内存空间,稳定性高但资源消耗大。线程是进程内的执行单元,共享内存,轻量级且并发性好,但同步复杂。协程是用户态的轻量级调度单位,适用于高并发和IO密集型任务,资源消耗最小,但不支持多核并行。
52 1
|
18天前
|
消息中间件 Unix Linux
【C语言】进程和线程详解
在现代操作系统中,进程和线程是实现并发执行的两种主要方式。理解它们的区别和各自的应用场景对于编写高效的并发程序至关重要。
46 6
|
19天前
|
调度 开发者
深入理解:进程与线程的本质差异
在操作系统和计算机编程领域,进程和线程是两个核心概念。它们在程序执行和资源管理中扮演着至关重要的角色。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
42 5
|
16天前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
18天前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
38 4
|
1月前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
1月前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
1月前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
29 1
|
1月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
48 2