第37天并发编程之线程篇

什么是线程和进程

进程指的是一个程序执行的过程,是一个资源单位。它包含了操作系统开辟内存空间,将应用程序加载到内存中以及执行应用程序代码的整个过程。就像是一个车间内的一个小工厂一样,整个的生产过程被称之为一个进程。

线程是操作系统真正的执行单元。它仅仅代表的是进程中的最后一步,也就是执行应用程序代码的过程。就像是车间里的一条条流水线一样,是真正的用来执行代码的一个过程。

线程和进程的区别

进程占用开销较大,这是因为进程要重新开辟一段内存空间,线程开销较小。

进程之间内存是物理隔离的,但是同一进程内的线程之间内存是共享的。注意不同进程之间的线程通信还是需要通过队列进行通信的。
from threading import Thread
import time

# 在主线程中设置一个全局变量x x = 100 def task(): global x x = 0 t = Thread(target=task) t.start() t.join() # 此时打印出来的结果是0,说明同一个进程之间线程数据是共享的 print(x)

开启线程的两种方式

通过类Thread

因为线程开销较小的原因,我们会发现结果是先打印task里面的内容,然后打印主线程三个字,这个和进程正好相反。

from threading import Thread
import time

def task():
print('thread is running ....')
time.sleep(3)

Thread(target=task).start()
print('主线程')

通过继承类Thread

我们创建一个线程并且执行的过程本质上就是创建内存之后执行Thread类的run函数,因此我们可以通过继承类的方式去创建。

from threading import Thread
import time

class MyThread(Thread):
def run(self):
print('thread is running ....')
time.sleep(3)

MyThread().start()
print('主线程')

线程相关的属性方法

# current_thread() 当前线程对象,.name是里面的一个属性,可以得到线程名称,主线程名称为MainTread
# active_count() 当前活跃的线程数,记得还有一个主线程
# enumerate 返回一个列表,里面都是当前活跃的线程数目
from threading import Thread, current_thread, active_count, enumerate
import time

def task():
print('%s is running' % current_thread().name)
time.sleep(3)

#: name表示自定义线程名称
t = Thread(target=task,)
t.start()
print(current_thread().name)
print(active_count())
print(enumerate())

守护进程与守护线程

守护进程
对于进程而言,如果代码中有守护进程,也有非守护进程,等主进程代码执行完毕之后守护进程也就结束了,并不会等待非守护进程的执行。
from multiprocessing import Process

def task1(): print(123) time.sleep(1) print('end123') def task2(): print(456) time.sleep(3) print('end456') if __name__ == '__main__': p1 = Process(target=task1) p2 = Process(target=task2) p1.daemon = True p1.start() p2.start() # 当执行完print之后就代表主进程代码已经执行完毕,此时就会终止守护进程 # 所以不会打印task1里面的内容 # 但是还是要等待非守护进程结束之后主进程才会真正的结束 # 因此我们看到了task2里面的内容 print('主进程over...') # 执行结果; # 主进程over... # 456 # end456

守护线程
对于线程而言,如果代码中有守护线程,也有非守护线程,等主线程代码执行完毕之后并不会终止守护线程的执行,只有等到所有的非守护线程执行完毕之后才意味着主线程的结束,此时才会总之守护线程。
将上面的代码的进程改成线程,就会出现不一样的效果。
from threading import Thread
import time

def task1(): print(123) time.sleep(5) print('end123') def task2(): print(456) time.sleep(3) print('end456') t1 = Thread(target=task1) t2 = Thread(target=task2) t1.daemon = True t1.start() t2.start() # 当print代码执行完毕之后,就代表这主线程代码执行完毕了,但是并不是主线程执行完毕了,这个是和进程的一个区别 # 因此要等待非守护线程t2执行完毕之后才代表主线程真的结束了,此时task1作为守护进程也就被终止了 # 因此我们会看到能够打印全部的task2内容,但是不会打印task1的内容 print('主线程..') # 运行结果 # 123 # 456 # 主线程.. # end456 二.锁

互斥锁
线程中的互斥锁和进程中的互斥锁都是为了解决多个进程或者线程同时访问同一个系统资源时出现数据混乱的问题,不同之处在于所使用模块不一样,因此线程互斥锁只能在线程中使用,进程互斥锁只能在进程中使用。
不使用线程锁的问题
from threading import Thread
import time

x = 100

def task():
global x
temp = x
time.sleep(0.1)
x = temp - 1

#: 创建100个线程全局变量x进行修改,每次减1
t_l = []
for i in range(100):
t = Thread(target=task)
t_l.append(t)
t.start()

# 用来等待所有线程结束
for i in t_l:
i.join()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfxjj.html