python进程线程多线程锁

进程:

进程就是一段程序的执行过程。

线程:

通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。

多线程:

在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。

最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。

线程和进程的关系区别:
1 一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器)

2 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

3 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和
程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

4 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调
度的一个独立单位.

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程
自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是
它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

问:进程快还是线程快?

进程和线程没有可比性。进程是资源的集合,线程是真正执行任务的,进程想执行任务也得通过线程。所以问进程快还是线程快 其实问的是两个线程哪个快。

在用c语言编写的python中有一个设计缺陷
不管 计算机cpu有几核 但在cpython中同一时间只会执行一个线程.

python的线程与threading模块

threading 模块建立在thread 模块之上。thread模块以低级、原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装,提供了更方便的api来处理线程。

线程的两种调用方式

直接调用(推荐使用这种方法写)

import threading
import time

def sayhi(num): #定义每个线程要运行的函数

    print("running on number:%s" %num)

    time.sleep(3)

if __name__ == '__main__':

    t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例,注意args=后面写的是以元组的形式传参数
    t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例

    t1.start() #启动线程
    t2.start() #启动另一个线程

继承调用(这种方法了解就行)

import threading
import time
class  MyThread(threading.Thread):#继承threading.Thread这个父类
    def __init__(self,name):
        super(MyThread,self).__init__()
        self.name=name
    def run(self):#定义每个线程要运行的函数。记住run方法不能更换别的函数
        for i in range(1,5):
            time.sleep(1)
            print("我正在拍片",self.name)
mythread=MyThread("pp")
mythread.start()
mythread1=MyThread("oo")
mythread1.start()

join&Daemon方法
join()
join的作用是保证当前线程执行完成后,再执行其它线程。在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
例:

import threading
import time
def Myjoin():
    print ('hello world!')
    time.sleep(1)
for i in range(5):
    t=threading.Thread(target=Myjoin)
    t.start()
    t.join()
print ('hello main')
#输出:(每隔一秒输出)
hello world!
hello world!
hello world!
hello world!
hello world!
hello main
注释掉join
#输出:
hello world!
hello world!
hello world!
hello world!
hello main!
(全部输出后等待一秒程序结束)

Setdaemon()
将线程声明为守护线程,必须在start()方法调用之前设置,如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就兵分两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后在退出。但是有时候我们需要的是只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以用setdoemon方法啦

import threading
import time
def run(a):
    print("你好%s" % a)
    time.sleep(2)
    print("我都要睡着了%s"%a)

start_time = time.time()
list1=[]
for i in range(10):
    t1=threading.Thread(target=run,args=("hello%s"%i,))
    t1.setDaemon(True)#吧当前线程设置为守护线程 必须放在start之前
    list1.append(t1)
    t1.start()

print("结束时间是",time.time()-start_time)

#只会输出这些
你好hello0
你好hello1
你好hello2
你好hello3
你好hello4
你好hello5
你好hello6
你好hello7
你好hello8
你好hello9
结束时间是 0.0020074844360351562
#注释掉t1.setDaemon(True)后会输入以上并两秒后输入
我都要睡着了hello4
我都要睡着了hello2
我都要睡着了hello0
我都要睡着了hello3
我都要睡着了hello1
我都要睡着了hello7
我都要睡着了hello9
我都要睡着了hello8
我都要睡着了hello6
我都要睡着了hello5

全局解释器锁(GIL)

在同一个进程中只要有一个线程获取了全局解释器(cpu)的使用权限,那么其他的线程就必须等待该线程的全局解释器(cpu)使用权消失后才能使用全局解释器(cpu),即时多个线程直接不会相互影响在同一个进程下也只有一个线程使用cpu,这样的机制称为全局解释器锁(GIL)。

优点
1、避免了大量的加锁解锁的好处
2、使数据更加安全,解决多线程间的数据完整性和状态同步
缺点
多核处理器退化成单核处理器,只能并发不能并行。
注意
同一时刻的某个进程下的某个线程只能被一个cpu所处理,所以在GIL锁下的线程只能被并发,不能被并行。

同步锁lock

什么是同步锁?
同一时刻的一个进程下的一个线程只能使用一个cpu,要确保这个线程下的程序在一段时间内被cpu执,那么就要用到同步锁。
为什么用同步锁?
因为有可能当一个线程在使用cpu时,该线程下的程序可能会遇到io操作,那么cpu就会切到别的线程上去,这样就有可能会影响到该程  序结果的完整性。
怎么使用同步锁?
只需要在对公共数据的操作前后加上上锁和释放锁的操作即可。、

import threading
import time
def run():
    lock.acquire()#获取一把锁
    print("你好")
    time.sleep(0.5)
    lock.release()#释放锁
    print("你想干啥")
lock=threading.Lock()#创建一个锁


list1=[]
for i in range(10):
    t1=threading.Thread(target=run)
    list1.append(t1)
    t1.start()
for t in list1:
    t.join()
print("结束......")

#-----------------------------
#每隔0.5秒打印十遍
你好
你想干啥
#最后打印主线程
结束.....

死锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。尽管死锁很少发生,但一旦发生就会造成应用的停止响应。

import threading
import time
class MyThread(threading.Thread):
    def actionA(self):
        B.acquire()
        print(self.name,"gotA",time.ctime())
        time.sleep(2)
        A.acquire()
        print(self.name, "gotB", time.ctime())
        time.sleep(1)
        A.release()
        B.release()

    def actionB(self):
        A.acquire()
        print(self.name, "gotA", time.ctime())
        time.sleep(2)
        B.acquire()
        print(self.name, "gotB", time.ctime())
        time.sleep(1)
        B.release()
        A.release()

    def run(self):
        self.actionA()
        self.actionB()

if __name__ =="__main__":
    A=threading.Lock()
    B=threading.Lock()


    l=[]
    for i in range(5):
        t=MyThread()
        t.start()
        l.append(t)
    for i in l:
        i.join()
    print("end.......")
#——————————————————————————————————
#执行结果
Thread-1 gotA Wed Jul 11 19:05:52 2018
Thread-1 gotB Wed Jul 11 19:05:54 2018
Thread-1 gotA Wed Jul 11 19:05:55 2018
Thread-2 gotA Wed Jul 11 19:05:55 2018
#然后卡死程序不会执行

递归锁
 在Python中为了支持同一个线程中多次请求同一资源,Python提供了可重入锁。这个RLock内部维护着一个Lock和一个变量。变量记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
 
上面的例子如果使用RLock代替Lock,则不会发生死锁:


import threading
import time
class MyThread(threading.Thread):
    def actionA(self):
        r_lock.acquire()
        print(self.name,"gotA",time.ctime())
        time.sleep(2)
        r_lock.acquire()
        print(self.name, "gotB", time.ctime())
        time.sleep(1)
        r_lock.release()
        r_lock.release()

    def actionB(self):
        r_lock.acquire()
        print(self.name, "gotA", time.ctime())
        time.sleep(2)
        r_lock.acquire()
        print(self.name, "gotB", time.ctime())
        time.sleep(1)
        r_lock.release()
        r_lock.release()

    def run(self):
        self.actionA()
        self.actionB()

if __name__ =="__main__":

    r_lock=threading.RLock() #创建一个递归锁

    l=[]
    for i in range(5):
        t=MyThread()
        t.start()
        l.append(t)
    for i in l:
        i.join()
    print("end.......")

#以下是运行结果
Thread-1 gotA Wed Jul 11 19:12:44 2018
Thread-1 gotB Wed Jul 11 19:12:46 2018
Thread-2 gotA Wed Jul 11 19:12:47 2018
Thread-2 gotB Wed Jul 11 19:12:49 2018
Thread-2 gotA Wed Jul 11 19:12:50 2018
Thread-2 gotB Wed Jul 11 19:12:52 2018
Thread-4 gotA Wed Jul 11 19:12:53 2018
Thread-4 gotB Wed Jul 11 19:12:55 2018
Thread-4 gotA Wed Jul 11 19:12:56 2018
Thread-4 gotB Wed Jul 11 19:12:58 2018
Thread-1 gotA Wed Jul 11 19:12:59 2018
Thread-1 gotB Wed Jul 11 19:13:01 2018
Thread-3 gotA Wed Jul 11 19:13:02 2018
Thread-3 gotB Wed Jul 11 19:13:04 2018
Thread-3 gotA Wed Jul 11 19:13:05 2018
Thread-3 gotB Wed Jul 11 19:13:07 2018
Thread-5 gotA Wed Jul 11 19:13:08 2018
Thread-5 gotB Wed Jul 11 19:13:10 2018
Thread-5 gotA Wed Jul 11 19:13:11 2018
Thread-5 gotB Wed Jul 11 19:13:13 2018
end.......

猜你喜欢

转载自blog.csdn.net/mr_li1/article/details/81005512
今日推荐