net asp网站开发,seo计费怎么刷关键词的,如何建设个人的网站,徐州专业网站制作目录 multiprocessing模块
线程的开发
threading模块 setDaemon
死锁 线程间的通信 multiprocessing模块
运行python的时候#xff0c;我们都是在创建并运行一个进程#xff0c;(linux中一个进程可以fork一个子进程#xff0c;并让这个子进程exec另外一个程序)。在pyt…
目录 multiprocessing模块
线程的开发
threading模块 setDaemon
死锁 线程间的通信 multiprocessing模块
运行python的时候我们都是在创建并运行一个进程(linux中一个进程可以fork一个子进程并让这个子进程exec另外一个程序)。在python中我们通过标准库中的subprocess包来fork一个子进程并且运行一个外部的程序。subprocess包中定义有数个创建子进程的函数这些函数分别以不同的方式创建子进程所欲我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具从而在进程间使用文本通信。
multiprocessing 包同时提供本地和远程并发使用子进程代替线程有效避免 Global Interpreter Lock 带来的影响。
from multiprocessing import Process
import os
from time import sleep, time
def test1(name):print(当前进程的ID, os.getpid())print(父进程的ID, os.getppid())print(当前进程的名字, name)sleep(3)if __name__ __main__:start time()# 创建多个子进程并且把这些子进程放入列表中process_list []print(主进程的ID, os.getpid())for i in range(10):p Process(targettest1, args(process-%s % i,))p.start()process_list.append(p)
类包装自定义一个Process进程类该类中的run函数由一个子进程调用执行
from multiprocessing import Process
import os
from time import sleep, time
# 自定义一个进程类 继承Process类
class MyProcess(Process):def __init__(self, name):Process.__init__(self)self.name namedef run(self):print(当前进程的ID, os.getpid())print(父进程的ID, os.getppid())print(当前进程的名字, self.name)sleep(3)if __name__ __main__:print(主进程ID, os.getpid())start time()process_list []for i in range(10):p MyProcess(process-%s % i)p.start()process_list.append(p)for p in process_list:p.join()end time() - startprint(end)
线程的开发
Python 的标准库提供了两个模块thread 和 threadingthread 是低级模块threading 是高级模块对_thread进行了封装。绝大多数情况下我们只需要使用threading 这个高级模块。
多线程概念
多线程使得系统可以在单独的进程中执行并发任务。虽然进程也可以在独立的内存空间中并发执行但是其系统开销会比较大。生成一个新进程必须为其分配独立的地址空间并维护其代码段、堆栈段和数据段等这种开销是巨大的。另外进程间的通信实现也不方便。在程序功能日益复杂的时候需要有更好的系统模型来满足要求线程由此产生了。 线程是“轻量级”的一个进程中的线程使用同样的地址空间且共享许多资源。启动线程的时间远远小于启动进程的时间和空间而且线程间的切换也要比进程间的切换快得多。由于使用同样的地址空间所以线程之间的数据通信比较方便一个进程下的线程之间可以直接使用彼此的数据。当然这种方便性也会带来一些问 题特别是同步问题。 多线程对于那些I/O受限的程序特别适用。其实使用多线程的一个重要目的就是最大化地利用CPU的资源。当某一线程在等待I/O的时候另外一个线程可以占用CPU资源。如最简单的GUI程序一般需要有一个任务支持前台界面的交互还要有一个任务支持后台的处理。
多线程运行的作用
使用线程可以把占据长时间的程序中的任务放到后台去处理。用户界面可以更加吸引人比如用户点击了一个按钮去触发某些事件的处理可以弹出一个进度条来显示处理的进度。程序的运行速度可能加快。在一些等待的任务实现上如用户输入、文件读写和网络收发数据等。在这种情况下我们可以释放一些珍贵的资源如内存占用。
线程可以分为内核线程和用户线程内核线程由操作系统内核创建和撤销用户线程不需要内核支持而在用户程序中实现的线程。
创建线程
Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。
threading模块
import time
def say():print(这是单线程)time.sleep(1)
if __name__ __main__:start time.time()for i in range(5):say()end time.time()print(f使用时间{end - start})
import threading
import time
def say():print(这是多线程)time.sleep(1)
if __name__ __main__:入口start time.time()for i in range(5):# 通过threading下的Thread方法创建线程t threading.Thread(targetsay)t.start() # 启动线程end time.time()print(f使用时间{end - start}) 可以明显看出使用了多线程并发的操作花费时间要短很多。
程序是通过threading模块下的Thread的类去实例化一个此对象并调用方法实现生成多线程target参数表示线程需要执行的方法通过对象的start的方法开启线程。
import threading
from time import sleep,ctime
def sing():for i in range(3):print(唱歌...%d%i)sleep(1)
def dance():for i in range(3):print(跳舞...%d%i)sleep(1)
if __name__ __main__:print(---开始---:%s%ctime())t1 threading.Thread(targetsing)t2 threading.Thread(targetdance)t1.start()t2.start()sleep(5) print(---结束---:%s%ctime()) join方法
该方法将等待,一直到它调用的线程终止它的名字表示调用的线程会一直等待,直到指定的线程加入它。join所完成的工作就是线程同步即主线程任务结束之后进入阻塞状态一直等待其他的子线程执行结束之后主线程再终止。
from threading import Thread
from time import sleep, time
def run(name):print(Threading:{} start.format(name))sleep(3)print(Threading:{} end.format(name))
if __name__ __main__:# 开始时间start time()# 创建线程列表t_list []# 循环创建线程for i in range(10):t Thread(targetrun, args(t{}.format(i),))t.start()t_list.append(t)# 等待线程结束for t in t_list:t.join()# 计算使用时间end time() - startprint(end) setDaemon
将线程声明为守护线程在start() 方法调用之前设置这个方法和join是相反的。
有时候我们需要的是 只要主线程完成了不管子线程是否完成都要和主线程一起退出 这时就可以用setDaemon方法。
from threading import Thread
import time
def foo():print(123)time.sleep(1)print(end123)
def bar():print(456)time.sleep(3)print(end456)
t1 Thread(targetfoo)
t2 Thread(targetbar)
t1.daemon True
t1.start()
t2.start()
print(~~~) 同步锁与GIL的关系
GIL本质是一把互斥锁但GIL锁住的是解释器级别的数据同步锁锁的是解释器以外的共享资源例如:硬盘上的文件 控制台对于这种不属于解释器的数据资源就应该自己加锁处理 。
GIL 的作用是对于一个解释器只能有一个thread在执行bytecode。所以每时每刻只有一条bytecode在被执行一个thread。GIL保证了bytecode 这层面上是thread safe的。
死锁
在多线程程序中死锁问题很大一部分是由于线程同时获取多个锁造成的。 在线程间共享多个资源的时候如果两个线程分别占有一部分资源并且同时等待对方的资源就会造成死锁。
产生死锁的四个必要条件
互斥条件一个资源每次只能被一个线程使用。请求与保持条件一个线程因请求资源而阻塞时对已获得的资源保持不放。不剥夺条件:线程已获得的资源在末使用完之前不能强行剥夺。循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
from threading import Thread,Lock
from time import sleep
class Task1(Thread):def run(self):while True:if lock1.acquire():print(------Task 1 -----)sleep(0.5)lock2.release()
class Task2(Thread):def run(self):while True:if lock2.acquire():print(------Task 2 -----)sleep(0.5)lock3.release()class Task3(Thread):def run(self):while True:if lock3.acquire():print(------Task 3 -----)sleep(0.5)lock1.release()lock1 Lock()
#创建另外一把锁
lock2 Lock()
lock2.acquire()lock3 Lock()
lock3.acquire()
t1 Task1()
t2 Task2()
t3 Task3()
t1.start()
t2.start()
t3.start() 线程间的通信
在加锁的情况下程序就变成了串行也就是单线程而有时我们在不用考虑数据安全时不用加锁程序就变成了并行也就是多线程。为了避免业务开启过多的线程时。我们就可以通过信号量(Semaphore来设置指定个数的线程。
from threading import Thread, BoundedSemaphore
from time import sleep
def an_jian(num):semapshore.acquire()print(第{}个人安检完成.format(num))sleep(2)semapshore.release()if __name__ __main__:semapshore BoundedSemaphore(3)for i in range(20):thread Thread(targetan_jian, args(i,))thread.start()