python---进程与线程

charles8866 2018-02-02 原文

python—进程与线程

进程和线程


什么是线程(thread)什么是进程

线程:操作系统能够进行运算调度的最小单位。它被包含在进程中,是进程中的实际运作单位。是一串指令的集合

  一个线程指的是进程中一个单一顺序的控制流,一个进程是中可以并发多个线程,每个线程并行执行不同的任务

进程:以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存的管理,网络接口的调用等,对各种资源管理的集合,就可以称为进程

  进程要操作cpu,必须先创建一个线程,所有在同一个进程里的线程是共享同一块内存空间的

注意:1.进程本身不能够执行

   2.进程和线程不能比较谁快谁慢,两个没有可比性,进程是资源的集合,线程是真正执行任务的,进程要执行任务也要通过线程

   3.启动一个线程比启动一个进程快

进程和线程的区别

1.线程共享内存空间,进程的内存是独立的

2.thread have direct access to data segment of its process;process have their own copy of  the data segment of the parent process

3.同一个进程之间线程可以互相交流,两个进程想要通信,必须通过一个中间代理来实现

4.创建一个线程很简单,创建一个新进程需要对其父进程做一次克隆

5.一个线程可以控制和操作同一个进程里的其他的线程,但是进程只能操作子进程

6.改变一个主线程可能会影响到其他线程的运行,对父进程的修改不会影响到子进程

Python GIL(全局解释器锁)

在python中无论你启用多少个线程,你有多少个cpu,在python执行的时候都会在同一时刻只准许一个线程运行

原因:python的线程是调用操作系统的原生线程

线程锁:

 1 import threading
 2 import time
 3 def run(n):
 4     lock.acquire()
 5     global num
 6     num += 1
 7     #time.sleep(1)在上锁的情况不要使用sleep,不然会等50s才会完成
 8     lock.release()
 9 lock = threading.Lock()
10 num = 0
11 start_time = time.time()
12 t_objs = []
13 for i in range(50):
14     t = threading.Thread(target = run,args = ("t-%s" %i,))
15     t.start()
16     t_objs.append(t)
17 for t in t_objs:
18     t.join()
19 print("-----all threads has finished....",threading.current_thread(),threading.active_count())
20 
21 print("num = ",num)

 

给线程上锁,使程序变成串行,保证num在+1的时候能够准确无误,不然可能会导致,一个线程正在执行+1还没有结束,另外一个线程也开始+1,最后达不到准确结果

递归锁:在一个大锁中包含一个小锁

场景:学校放学,学生离校了,突然发现自己的文具盒落在了教师中,学校每次只准许一个人进学校(其他东西丢了就是这个人干的),进教室拿的时候也要开教室门(防止有其他人在学校没有走),最后拿到文具盒,离开学校。这个期间学校大门相当于一把锁,教室的门相当于另一把锁。保证了整个过程没有其他人的干扰

 1 import threading,time
 2 
 3 def run1():
 4     print("grab the first part data")
 5     lock.acquire()
 6     global num
 7     num += 1
 8     lock.release()
 9     return num
10 
11 def run2():
12     print("grab the second part data")
13     lock.acquire()
14     global num2
15     num2 += 1
16     lock.release()
17     return num2
18 
19 def run3():
20     lock.acquire()
21     res = run1()
22     print('------between run1 and run2')
23     res2 = run2()
24     lock.release()
25     print(res,res2)
26 
27 num,num2 = 0,0
28 lock = threading.RLock()
29 for i in range(10):
30     t = threading.Thread(target=run3)
31     t.start()
32 
33 while threading.active_count() != 1:
34     print(threading.active_count())
35 else:
36     print("----all threads done---")
37     print(num,num2)

 

相当于先进入run3这个大门,然后在进入run1和run2这个两个小门,然后进行num1和num2的加1,保证了每个线程的执行都是串行的

Python threading模块

线程有2中调用方式

直接调用:

 1 import threading
 2 import time
 3 
 4 def run(n):
 5     print("task ",n)
 6     time.sleep(2)
 7     
 8 t1 = threading.Thread(target = run,args = ("t1",))
 9 t2 = threading.Thread(target = run,args = ("t2",))
10 
11 t1.start()
12 t2.start()

 

运行结果:一下子出来两个结果,但是程序还会等待2s才会结束,一共两秒,因为他们是并行的

继承式调用:

 1 import threading
 2 import time
 3 
 4 #用类的方式启动线程
 5 class MyThread(threading.Thread):
 6     def __init__(self,n):
 7         super(MyThread,self).__init__()
 8         self.n = n
 9     def run(self):
10         print("running task ",self.n)
11 
12 t1 = MyThread("t1")
13 t2 = MyThread("t2")
14 t1.start()
15 t2.start()

上面只启动了2个线程,我们下面启动50个线程:

 1 import threading
 2 import time
 3 
 4 def run(n):
 5     print("task ",n)
 6     time.sleep(2)
 7 
 8 start_time = time.time()
 9 for i in range(50):
10 
11     t = threading.Thread(target = run,args = ("t-%s" %i,))
12     t.start()
13 print("cost : ",time.time()-start_time)

 运行结果:

问题:创建了50个进程之后只用了这点时间,主程序没有等其他的子线程就往下走

原因:是多线程的原因,一个程序至少有一个线程,程序本身就是一个线程,主线程,主线程启动了子线程之后,子线程就和主线程没有关系了,两个互不影响

解决方法:join()方法,等子线程运行完成之后,主程序才往下走

import threading
import time
def run(n):
    print("task ",n)
    time.sleep(2)
    print("task has done.... ",n)
start_time = time.time()
t_objs = []
for i in range(50):

    t = threading.Thread(target = run,args = ("t-%s" %i,))
    t.start()
    t_objs.append(t)

for t in t_objs:
    t.join()
print("------all threads has finished")
print("cost : ",time.time()-start_time)

 

  先自己创建一个临时列表,然后存储创建的线程,然后一个一个的用join()方法  

 创建了50个线程,主线程就是程序的本身,也就是说上面一共有51个线程

#threading.current_thread()显示当前线程是主线程还是子线程
#threading.active_count()显示当前程序运行的线程的个数
print("-----all threads has finished....",threading.current_thread(),threading.active_count())

 守护进程

t.setDaemon(True)     #把当前线程设置成守护线程,要在start()之前
非守护线程结束,所有守护线程就退出

 1 import threading
 2 import time
 3 def run(n):
 4     print("task ",n)
 5     time.sleep(2)
 6     print("task has done.... ",n)
 7 start_time = time.time()
 8 t_objs = []
 9 for i in range(50):
10 
11     t = threading.Thread(target = run,args = ("t-%s" %i,))
12     t.setDaemon(True)#把当前线程设置成守护线程,要在start()之前
13     t.start()
14     t_objs.append(t)
15 
16 print("-----all threads has finished....",threading.current_thread(),threading.active_count())
17 print("cost : ",time.time()-start_time)

 

 运行结果:task has done都没有运行,主线程结束之后,所有子线程都强制结束

 Semaphore(信号量)

互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,如有3个座位,最多允许3个人同时在座位上,后面的人只能等到有人起来才能够坐进去

 1 import threading,time
 2 def run(n):
 3     semaphore.acquire()
 4     time.sleep(1)
 5     print("run the thread:%s\n" %n)
 6     semaphore.release()
 7 
 8 if __name__ == '__main__':
 9  10     semaphore = threading.BoundedSemaphore(5)#最多允许5个线程同时运行
11     for i in  range(20):
12         t = threading.Thread(target = run,args=(i,))
13         t.start()
14 
15 
16 while threading.active_count() != 1:
17     pass#print(threading.active_count())
18 else:
19     print("----all threads done---")
20    21 #一次性执行了5个线程

 

和线程锁差不多,都要acquire()和release(),区别就是信号量有多把锁,

threading.BoundedSemaphore(5)最多允许5个线程同时运行,那运行结果就是5个结果一起出来,但是实质是这5个要是有3个先完成就会立刻再送进去3个,它不会等5个都完成,它是每出来一个就放进去一个

这5个如果同时改数据就有可能改错,这个主要用于:链接池 ,线程池。mysql链接有链接池的概念,同一时刻最多有几个并发;socketserver,为了保证系统不会被太多线程拉慢,可以用信号量弄同一时刻最多有100个链接进来

事件(event)

a events is a simple synchronization object;
the event represents an internal flag,and threads can wait for the flag to be set,or set or clear the flag themselves

事件是一个简单的同步对象,事件就相当于设置一个全部变量,然后线程不断的检测这个变量的变化然后进行不同的操作

方法:

  event = threading.Event()生成一个event对象

  event.set()

  event.clear()

  event.wait()

if the flag is set,the wait method doesn't do anything
标志位设定,代表绿灯,直接通行
if the flag is cleared,wait will block until it becomes set again
标志位被清空,代表红灯,wait等待变绿灯
any number of threads my wait for the same event

红绿灯案例:

 1 import threading
 2 import time
 3 
 4 event = threading.Event()
 5 def lighter():
 6     count = 0
 7     event.set()#一开始先设成绿灯
 8     while True:
 9         if count > 5 and count <=10 :#改成红灯
10             event.clear()#清空标志位
11             print("\033[41;1mred light is on ...\033[0m")
12         elif count > 10:
13             event.set()#变绿灯
14             print("\033[42;1mgreen light is on ...\033[0m")
15             count = 0
16         else:
17             print("\033[42;1mgreen light is on ...\033[0m")
18         time.sleep(1)
19         count += 1
20 def car(name):
21     while True:
22         if event.is_set():#代表绿灯
23             print("[%s] running..." %name)
24             time.sleep(1)
25         else:
26             print("[%s] sees red light,waiting..." %name)
27             event.wait()
28             print("\033[34;1m[%s] green light is on,start going ...\033[0m" %name)
29 
30 light = threading.Thread(target = lighter,)
31 light.start()
32 car1 = threading.Thread(target = car,args=("Tesla",))
33 car1.start()

 

运行结果:

queue队列

queue is especially useful in threaded programming when information must be exchanged safely between multiple threads

class queue.Queue(maxsize = 0)先入先出
class queue.LifeQuene(maxsize = 0)last in first out
class queue.PriorityQueue(maxsize = 0)存储数据时可设置优先级的队列

队列就是一个有顺序的容器
列表和队列的区别:列表取出数据后,数据还在列表中,相当如复制数据;队列的数据只有一份,取走就没有了

 class queue.Queue:

利用put(),get()方法往队列里加减数据,用qsize()方法得到此刻队列中还有多少数据。

但是有一个问题:当数据都取出来之后,如果还用get()方法去取数据的话,程序就会卡主

可以用get_nowait()方法,如果queue中没有了数据,就会抛出一个异常,这样就不会被卡住,同时也可以用qsize()方法进行判断,如果没有了数据就不要取了

Queue.get(block = True,timeout=None)    block参数,如果取不到数据,默认就会卡住,改成false就不会卡住;timeout设置卡住几秒

class queue.LifoQueue(maxsize = 0)#last in first out

1 import queue
2 q = queue.LifoQueue()
3 q.put(1)
4 q.put(2)
5 q.put(3)
6 print(q.get())
7 print(q.get())
8 print(q.get())

 

运行结果:

class queue.PriorityQueue(maxsize = 0)#存储数据室可以设置优先级队列

 1 import queue
 2 q = queue.PriorityQueue()
 3 
 4 q.put((10,"d1"))
 5 q.put((-1,"d2"))
 6 q.put((3,"d4"))
 7 q.put((6,"d5"))
 8 print(q.get())
 9 print(q.get())
10 print(q.get())
11 print(q.get())

 运行结果:

生产者消费者模型:

在并发编程中使用生产者和消费者模式能够解决大多数并发问题,该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度

 例子:

 1 import threading,time
 2 import queue
 3 q = queue.Queue(maxsize = 10)
 4 def Producer(name):
 5     count = 1
 6     while True:
 7         q.put("骨头:%s" %count)
 8         print("生产了骨头:",count)
 9         count += 1
10         time.sleep(0.5)
11 
12 
13 
14 def Consumer(name):
15     while True:
16         if q.qsize() > 0:
17             print("[%s] 取到 [%s],并且吃到了它。。。" %(name,q.get()))
18         time.sleep(1)
19 p = threading.Thread(target = Producer,args=("xiaoming",))
20 c = threading.Thread(target = Consumer,args=("xiaohong",))
21 c1 = threading.Thread(target = Consumer,args=("liangliang",))
22 p.start()
23 c.start()
24 c1.start()

 运行结果:

 

 

发表于 2018-02-02 14:48 ﹏亦°洛轩づ 阅读() 评论() 编辑 收藏

 

版权声明:本文为charles8866原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/charles8866/p/8402291.html

python---进程与线程的更多相关文章

随机推荐

  1. 思维导图工具XMind下载 – 本本

    思维导图工具XMind下载 XMind 是一款非常实用的商业思维导图软件,全力打造易用、高效的可视化思维软件, […]...

  2. 知道这三件事,UI设计新手就能掌握设计规范

    提起”设计规范“这个词语,许多UI设计师都一脸懵逼,更不用说那些UI设计新手了。而这个在国人眼中看似“陌生”的 […]...

  3. 2020想学习JAVA的同学看过来,最基础的编程CRUD你会了没?

    一 JDBC简介 Java DataBase Connectivity Java语言连接数据库 官方(Sun公 […]...

  4. jQuery遍历table

    1、 $(“table”).find(“tr”).each(f […]...

  5. Android SDK安装教程 – ——阿文

    Android SDK安装教程 =============转自============、 http://www […]...

  6. from django.db.models.fields import FieldDoesNotExist

    from django.db.models.fields import FieldDoesNotExist 错 […]...

  7. 1.JVM中的五大内存区域划分详解及快速扫盲

    本博客参考《深入理解Java虚拟机》这本书 视频及电子书详见:https://shimo.im/docs/HP […]...

  8. STM32-24位AD7799驱动之手册代码详解,支持模拟SPI和硬件SPI

    1.AD7799介绍 AD7799结构图如下所示:   其中REFIN参考电压建议为2.5V, REFIN电压 […]...

展开目录

目录导航