游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

一篇文章带你深度解析Python线程和进程

  使用Python中的线程模块,能够同时运行程序的不同部分,并简化设计。如果你已经入门Python,并且想用线程来提升程序运行速度的话,希望这篇教程会对你有所帮助。
  线程与进程
  什么是进程
  进程是系统进行资源分配和调度的一个独立单位进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
  什么是线程
  CPU调度和分派的基本单位线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
  进程与线程的关系图
  线程与进程的区别:地址空间和其他资源:进程间相互独立,同一进程的各线程间共享。某线程内的想爱你城咋其他进程不可见。通信:进程间通信IPC,线程间可以直接读写进程数据段来进行通信需要进程同步和互斥手段的辅助,以保证数据的一致性。调度和切换:线程上下文切换比进程上下文切换要快得多。在多线程操作系统中,进程不是一个可执行的实体。
  进程进程的引入
  现实生活中,有很多的场景中的事情是同时进行的,比如开车的时候手和脚共同来驾驶汽车,比如唱歌跳舞也是同时进行的,再比如边吃饭边打电话;试想如果我们吃饭的时候有一个领导来电,我们肯定是立刻就接听了。但是如果你吃完饭再接听或者回电话,很可能会被开除。模拟吃饭打电话fromtimeimportsleepdefeating():foriinrange(1,6):print(正在吃饭用时d分钟i)sleep(1)defcall():print(主人来电话了。。。)foriinrange(5):print(接听电话中。。。di)sleep(1)ifnamemain:eating()唱歌call()跳舞
  注意:很显然刚刚的程序并没有完成吃饭和接电话同时进行的要求如果想要实现吃饭和接电话同时进行,那么就需要一个新的方法,叫做:多任务
  多任务的概念
  什么叫多任务呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务,至少同时有3个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。
  现在,多核CPU已经非常普及了,但是,即使过去的单核CPU,也可以执行多任务。由于CPU执行代码都是顺序执行的,那么,单核CPU是怎么执行多任务的呢?
  答案就是操作系统轮流让各个任务交替执行,任务1执行0。01秒,切换到任务2,任务2执行0。01秒,再切换到任务3,执行0。01秒,这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
  真正的并行执行多任务只能在多核CPU上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。其实就是CPU执行速度太快啦!以至于我们感受不到在轮流调度。
  并行与并发
  并行(Parallelism)
  并行:指两个或两个以上事件(或线程)在同一时刻发生,是真正意义上的不同事件或线程在同一时刻,在不同CPU资源呢上(多核),同时执行。
  特点同一时刻发生,同时执行。不存在像并发那样竞争,等待的概念。
  并发(Concurrency)
  指一个物理CPU(也可以多个物理CPU)在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。
  特点微观角度:所有的并发处理都有排队等候,唤醒,执行等这样的步骤,在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根据优先级的不同,而先后进入队列排队等候执行。宏观角度:多个几乎同时到达的请求(或线程)在宏观上看就像是同时在被处理。
  Python中进程操作
  multiprocess。Process模块
  process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。
  语法:Process(〔group〔,target〔,name〔,args〔,kwargs〕〕〕〕〕)
  由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)。
  注意:1。必须使用关键字方式来指定参数;2。args指定的为传给target函数的位置参数,是一个元祖形式,必须有逗号。
  参数介绍:
  group:参数未使用,默认值为None。
  target:表示调用对象,即子进程要执行的任务。
  args:表示调用的位置参数元祖。
  kwargs:表示调用对象的字典。如kwargs{name:Jack,age:18}。
  name:子进程名称。
  代码:importosfrommultiprocessingimportProcessdeffuncone():print(第一个子进程)print(子进程(一)大儿子:s父进程:s(os。getpid(),os。getppid()))deffunctwo():print(第二个子进程)print(子进程(二)二儿子:s父进程:s(os。getpid(),os。getppid()))ifnamemain:poneProcess(targetfuncone)PtwoProcess(targetfunctwo)pone。start()Ptwo。start()print(子进程:s父进程:s(os。getpid(),os。getppid()))
  除了上面这些开启进程的方法之外,还有一种以继承Process的方式开启进程的方式:importosfrommultiprocessingimportProcessclassMyProcess(Process):definit(self,name):super()。init()self。namenamedefrun(self):print(进程为s,父进程为s(os。getpid(),os。getppid()))print(我的名字是sself。name)ifnamemain:poneMyProcess(运动员A)ptwoMyProcess(运动员B)pthrMyProcess(运动员C)pone。start()自动调用run()ptwo。start()pthr。run()直接调用run()pone。join()ptwo。join()pthr。join()调用run()函数的不可以调用join()print(主进程结束)锁Lock
  通过上面的研究,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题。
  当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题,我们可以考虑加锁,我们以模拟抢票为例,来看看数据安全的重要性。frommultiprocessingimportProcess,Lockimporttimeimportjsonimportrandom查询票defsearch():dicjson。load(open(db))加载数据库或数据文件数据time。sleep(random。random())模拟读取数据print(剩余票数:sdic〔count〕)买票defget():dicjson。load(open(db))加载数据库或数据文件数据time。sleep(random。random())模拟网络延迟ifdic〔count〕0:dic〔count〕1购票成功后减一time。sleep(1)json。dump(dic,open(db,w))print(购票成功)else:print(尚无余票)封装成任务,在加锁期间没有,其他进程是无法操作数据的deftask(lock):lock。acquire()请求加锁search()get()lock。release()释放锁ifnamemain:lockLock()foriinrange(10):pProcess(targettask,args(lock,))p。start()
  加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改。加锁牺牲了速度,但是却保证了数据的安全。
  因此我们最好找寻一种解决方案能够兼顾:1、效率高(多个进程共享一块内存的数据)2、帮我们处理好锁问题。
  mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。队列和管道都是将数据存放于内存中队列又是基于(管道锁)实现的,可以让我们从复杂的锁问题中解脱出来,我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性(后续扩展该内容)。
  线程
  Python的threading模块
  Python供了几个用于多线程编程的模块,包括thread,threading和Queue等。thread和threading模块允许程序员创建和管理线程。thread模块供了基本的线程和锁的支持,而threading供了更高级别,功能更强的线程管理的功能。Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构。
  python创建和执行线程
  创建线程代码
  1。创建方法一:importosimporttimefromthreadingimportThread,currentthreaddeftask1():foriinrange(5):print({}洗衣服:。format(currentthread()。name),i,os。getpid(),os。getppid())time。sleep(0。5)deftask2(n):foriinrange(n):print({}劳动最光荣,扫地中。。。。format(currentthread()。name),i,os。getpid(),os。getppid())time。sleep(0。5)ifnamemain:print(main:,os。getpid())创建线程对象t1Thread(targettask1,name警察)t2Thread(targettask2,name小偷,args(6,))启动线程t1。start()t2。start()
  2。创建方法二:importtimefromthreadingimportThread自定义线程类classMyThread(Thread):definit(self,name):Thread。init(self)self。namenamedefrun(self):foriinrange(5):print({}正在打印:{}。format(self。name,i))time。sleep(0。1)ifnamemain:创建三个线程,给线程起名字t1MyThread(小明)t2MyThread(小花)t3MyThread(ergou)启动线程t1。start()t2。start()t3。start()资源共享问题
  进程和线程都是实现多任务的一种方式,例如:在同一台计算机上能同时运行多个QQ(进程),一个QQ可以打开多个聊天窗口(线程)。资源共享:进程不能共享资源,而线程共享所在进程的地址空间和其他资源,同时,线程有自己的栈和栈指针。所以在一个进程内的所有线程共享全局变量,但多线程对全局变量的更改会导致变量值得混乱。
  代码演示:fromthreadingimportThreadimporttimegnum1000defwork1():globalgnumgnum3print(work1num:,gnum)defwork2():globalgnumprint(work2num:,gnum)ifnamemain:print(startnum:,gnum)t1Thread(targetwork1)t1。start()故意停顿一秒,以保证线程1执行完成time。sleep(1)t2Thread(targetwork2)t2。start()
  得到的结果是:startnum:1000
  work1num:1003
  work2num:1003全局解释器锁(GIL)
  首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行(其中的JPython就没有GIL)。
  那么CPython实现中的GIL又是什么呢?GIL全称GlobalInterpreterLock为了避免误导,我们还是来看一下官方给出的解释:
  InCPython,theglobalinterpreterlock,orGIL,isamutexthatpreventsmultiplenativethreadsfromexecutingPythonbytecodesatonce。ThislockisnecessarymainlybecauseCPython’smemorymanagementisnotthreadsafe。(However,sincetheGILexists,otherfeatureshavegrowntodependontheguaranteesthatitenforces。)
  主要意思为:
  GIL是一个互斥锁,它防止多个线程同时执行Python字节码。这个锁是必要的,主要是因为CPython的内存管理不是线程安全的尽管Python完全支持多线程编程,但是解释器的C语言实现部分在完全并行执行时并不是线程安全的。
  因此,解释器实际上被一个全局解释器锁保护着,它确保任何时候都只有一个Python线程执行。在多线程环境中,Python虚拟机按以下方式执行:设置GIL切换到一个线程去执行运行
  由于GIL的存在,Python的多线程不能称之为严格的多线程。因为多线程下每个线程在执行的过程中都需要先获取GIL,保证同一时刻只有一个线程在运行。
  由于GIL的存在,即使是多线程,事实上同一时刻只能保证一个线程在运行,既然这样多线程的运行效率不就和单线程一样了吗,那为什么还要使用多线程呢?
  由于以前的电脑基本都是单核CPU,多线程和单线程几乎看不出差别,可是由于计算机的迅速发展,现在的电脑几乎都是多核CPU了,最少也是两个核心数的,这时差别就出来了:通过之前的案例我们已经知道,即使在多核CPU中,多线程同一时刻也只有一个线程在运行,这样不仅不能利用多核CPU的优势,反而由于每个线程在多个CPU上是交替执行的,导致在不同CPU上切换时造成资源的浪费,反而会更慢。即原因是一个进程只存在一把gil锁,当在执行多个线程时,内部会争抢gil锁,这会造成当某一个线程没有抢到锁的时候会让cpu等待,进而不能合理利用多核cpu资源。
  但是在使用多线程抓取网页内容时,遇到IO阻塞时,正在执行的线程会暂时释放GIL锁,这时其它线程会利用这个空隙时间,执行自己的代码,因此多线程抓取比单线程抓取性能要好,所以我们还是要使用多线程的。
  GIL对多线程Python程序的影响
  程序的性能受到计算密集型(CPU)的程序限制和IO密集型的程序限制影响,那什么是计算密集型和IO密集型程序呢?
  计算密集型:要进行大量的数值计算,例如进行上亿的数字计算、计算圆周率、对视频进行高清解码等等。这种计算密集型任务虽然也可以用多任务完成,但是花费的主要时间在任务切换的时间,此时CPU执行任务的效率比较低。
  IO密集型:涉及到网络请求(time。sleep())、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。
  当然为了避免GIL对我们程序产生影响,我们也可以使用,线程锁。
  LockRLock
  常用的资源共享锁机制:有Lock、RLock、Semphore、Condition等,简单给大家分享下Lock和RLock。
  LockLock不能连续acquire锁,不然会死锁,Lock资源竞争可能会导致死锁。Lock会降低性能。fromthreadingimportThread,LocklockLock()total0两个线程共用一把锁,其中通过acquire申请获取锁对象,通过release释放锁资源进行加法defadd():globaltotalgloballockforiinrange(1000000):lock。acquire()total1lock。release()进行减法defsub():globaltotalgloballockforiinrange(1000000):lock。acquire()total1lock。release()创建线程对象thread1Thread(targetadd)thread2Thread(targetsub)将Thread1和2设置为守护线程,主线程完成时,子线程也一起结束thread1。setDaemon(True)thread1。setDaemon(True)启动线程thread1。start()thread2。start()阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。thread1。join()thread2。join()
  特点就是执行速度慢,但是保证了数据的安全性
  RLockRLock可以连续acquire锁,但是需要相应数量的release释放锁因可以连续获取锁,所以实现了函数内部调用带锁的函数fromthreadingimportThread,Lock,RLocklockRLock()total0defadd():globallockglobaltotalRLock实现连续获取锁,但是需要相应数量的release来释放资源foriinrange(1000000):可以连续获取锁lock。acquire()lock。acquire()total1要有对象的releaselock。release()lock。release()defsub():globallockglobaltotalforiinrange(1000000):lock。acquire()total1lock。release()thread1Thread(targetadd)thread2Thread(targetsub)thread1。start()thread2。start()阻塞,等待线程1和2完成,如果不使用join,那么主线程完成后,子线程也会自动关闭。thread1。join()thread2。join()
  使用锁代码操作不当就会产生死锁的情况。
  什么是死锁
  死锁:当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。即死锁是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。
  死锁的原因竞争系统资源进程运行推进的顺序不当资源分配不当产生死锁的四个必要条件互斥条件:一个资源每次只能被一个进程使用请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。解决死锁的办法减少资源占用时间,可以降低死锁放生的概率。银行家算法。银行家算法的本质是优先满足占用资源较少的任务。理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。
  所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。
  死锁代码deftask1(lock1,lock2):iflock1。acquire():print({}获取到lock1锁。format(currentthread()。name))foriinrange(5):print({}{}。format(currentthread()。name,i))time。sleep(0。01)iflock2。acquire(timeout2):print({}获取了lock1,lock2。format(currentthread()。name))lock2。release()lock1。release()deftask2(lock1,lock2):iflock2。acquire():print({}获取到lock2锁。format(currentthread()。name))foriinrange(5):print({}{}。format(currentthread()。name,i))time。sleep(0。01)iflock1。acquire(timeout2):print({}获取了lock1,lock2。format(currentthread()。name))lock1。release()lock2。release()ifnamemain:lock1Lock()lock2Lock()t1Thread(targettask1,args(lock1,lock2))t2Thread(targettask2,args(lock1,lock2))t1。start()t2。start()
  python线程间通信
  如果各个线程之间各干各的,确实不需要通信,这样的代码也十分的简单。但这一般是不可能的,至少线程要和主线程进行通信,不然计算结果等内容无法取回。而实际情况中要复杂的多,多个线程间需要交换数据,才能得到正确的执行结果。
  Queue消息队列
  python中Queue是消息队列,提供线程间通信机制,python3中重名为为queue,queue模块块下提供了几个阻塞队列,这些队列主要用于实现线程通信。
  在queue模块下主要提供了三个类,分别代表三种队列,它们的主要区别就在于进队列、出队列的不同。Queue(maxsize0):创建一个FIFO队列,若给定最大值,队列没有空间时阻塞,否则是无限队列LifoQueue(maxsize0):创建一个栈,maxsize含义同上PriorityQueue(maxsize0):创建一个优先队列,maxsize含义同上Queue对象方法:qsize():返回队列大小,是近似值(返回时可能队列大小被修改了)empty():判断队列是否为空full():判断队列是否为满put(item,blockTrue,timeoutNone):将item加入队列,可选阻塞和阻塞时间putnowait(item):即put(item,False)get(blockTrue,timeoutNone):从队列中获取元素,可选阻塞和阻塞时间getnowait():即get(False)taskdone():用于表示队列中某个元素已经执行完成,会被join()调用join():队列中所有元素执行完毕并调用taskdone()信号之前,保持阻塞Queue模块异常:Empty:对空队列调用get(timeoutn),如果等待n秒钟队列还是空的就会抛出异常Full:对满队列调用put(item,timeoutn),如果等待n秒钟仍然是满的就会抛出异常
  简单代码演示importrandomimporttimefromqueueimportQueuequeueQueue(3)queue。put(香蕉)queue。put(榴莲)queue。put(西瓜)queue。put(苹果)print(queue。get())print(queue。get())print(queue。get())
  此时代码会阻塞,因为queue中内容已满,此时可以在第四个queue。put(苹果)后面添加timeout,则成为queue。put(苹果,timeout1)如果等待1秒钟仍然是满的就会抛出异常,可以捕获异常。importrandomimporttimefromqueueimportQueuequeueQueue(3)try:queue。put(香蕉)queue。put(榴莲)queue。put(西瓜)queue。put(苹果,timeout1)print(queue。get())print(queue。get())print(queue。get())exceptExceptionase:print(e)
  同理如果队列是空的,无法获取到内容默认也会阻塞,如果不阻塞可以使用queue。getnowait()。使用Queue完成线程间通信
  在掌握了Queue阻塞队列的特性之后,在下面程序中就可以利用Queue来实现线程通信了。
  下面演示一个生产者和一个消费者,当然都可以多个importrandomimporttimefromthreadingimportThread,currentthreadfromqueueimportQueuedefproducer(queue):print({}开门啦!。format(currentthread()。name))foods〔红烧狮子头,香肠烤饭,蒜蓉生蚝,酸辣土豆丝,肉饼〕foriinrange(1,21):foodrandom。choice(foods)print({}正在加工中。。。。。。format(food))time。sleep(1)print(加工完成可以上菜了。。。)queue。put(food)queue。put(None)defconsumer(queue):print({}来吃饭啦。format(currentthread()。name))whileTrue:foodqueue。get()iffood:print(正在享用美食:,food)time。sleep(0。5)else:print({}把饭店吃光啦,走人。。。。format(currentthread()。name))breakifnamemain:queueQueue(8)t1Thread(targetproducer,name老家肉饼,args(queue,))t2Thread(targetconsumer,name坤坤,args(queue,))t1。start()t2。start()
  使用queue模块,可在线程间进行通信,并保证了线程安全。
  协程
  协程,又称微线程,纤程。英文名Coroutine。什么是协程
  协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机,我们可以把一个协程切换到另一个协程。只要这个过程中保存或恢复CPU上下文那么程序还是可以运行的。
  通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。协程和线程差异
  在实现多任务时,线程切换从系统层面远不止保存和恢复CPU上下文这么简单。操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。简单实现协程importtimedeftask1():whileTrue:print(task1)yieldtime。sleep(0。5)deftask2():whileTrue:print(task2)yieldtime。sleep(0。5)defmain():w1task1()w2task2()whileTrue:next(w1)next(w2)ifnamemain:main()
  greenlet与gevent
  为了更好使用协程来完成多任务,除了使用原生的yield完成模拟协程的工作,其实python还有的greenlet模块和gevent模块,使实现协程变的更加简单高效。
  greenlet虽说实现了协程,但需要我们手工切换,太麻烦了,gevent是比greenlet更强大的并且能够自动切换任务的模块。
  其原理是当一个greenlet遇到IO(指的是inputoutput输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。安装:pip3installgevent
  模拟耗时操作:importgeventdeff(n):foriinrange(n):print(gevent。getcurrent(),i)用来模拟一个耗时操作,注意不是time模块中的sleepgevent。sleep(1)g1gevent。spawn(f,5)g2gevent。spawn(f,5)g3gevent。spawn(f,5)g1。join()g2。join()g3。join()
  如果有耗时操作也可以换成,gevent中自己实现的模块,这时候就需要打补丁了。fromgeventimportmonkey有耗时操作时需要monkey。patchall()而且要放在代码的前面。。。。
  使用协程完成一个简单的二手房信息的爬虫代码吧!importurllib。requestimportsslimportrandomimporttimeimportosimportgeventfromgeventimportmonkeymonkey。patchall()defgettext(url):ragentlist〔Mozilla5。0(Macintosh;IntelMacOSX10113)AppleWebKit537。36(KHTML,likeGecko)Chrome75。0。3770。100Safari537。36,Mozilla5。0(Macintosh;IntelMacOSX10。11;rv:67。0)Gecko20100101Firefox67。0〕requesturllib。request。Request(url,headers{UserAgent:random。choice(agentlist)})responseurllib。request。urlopen(request,contextcontext)returnresponse。read()。decode()deffunc(url):urlhttps:bj。lianjia。comershoufangpg2withopen(url。rsplit(,maxsplit1)〔1〕。html,w,encodingutf8)asf:f。write(gettext(url))ifnamemain:爬取前30页,并将爬取的内容存储到指定的文件夹starttime。time()os。mkdir(ershoufang1)os。chdir(ershoufang1)urlhttps:bj。lianjia。comershoufangurlheadhttps:bj。lianjia。comershoufangpgglist〔〕foriinrange(1,11):urlurlheadstr(i)ggevent。spawn(func,url)glist。append(g)forginglist:g。join()endtime。time()print(endstart)
  以下文章来源于Python专栏,作者宋宋
  文章链接:https:mp。weixin。qq。coms2r3ipU3HjdA5VnqSHjUnQ

非营利性咨询公司Onward视觉形象设计Onward成立于2017年,是一家小型的非营利性咨询公司。他们与公司、非营利性机构、学校系统以及社区合作,建立个人和组织变革的能力。服务包括组织战略、高管培训计划、学习机会以……大众ID。3比亚迪海豚领衔,10款成都车展纯电新车抢先看成都车展已于今日开展,众多新车集中亮相,一时让人眼花缭乱。其中,众多纯电动新车的亮相尤其惹眼,包括关注度较高的比亚迪海豚、比亚迪元PLUS、大众ID。3、欧拉复古系列,以及造车……小时候街角的美食回忆,台湾庶民小吃香菇油饭油饭是台湾的庶民小吃,我家街角就有一家卖油饭的饭馆。小时候我和姐姐简直每天都要去吃一碗油饭。油饭的品种也是形形色色,有花生油饭、猪脚油饭、海鲜油饭等等。今天在《詹姆士的厨房》我……线上化不是解决一切问题的灵丹妙药,需要用数字化科技去赋能门店谈到疫情对于人工智能与数字化领域发展的影响,悠络客COO邹一波认为,对于未来,疫情是一个非常重要的时间节点,从行业整体来看,我身边很多资深业内人士均认为不要低估疫情的影响,毫不……共享电动自行车HumanForest视觉形象设计HumanForest于2020年推出,是英国首个免费共享电动自行车计划,目标是减少城市的二氧化碳排放量,使之成为一个绿色,健康的工作,生活和娱乐场所。在最初的推广期间,必须在……强田液压联手中望软件,共推国产液压系统自主化发展液压系统主要是为各类机器传递动力,相当于说,从发动机或者电机通过什么介质将动能传输到执行机构,实现这种直线运动和旋转运动,液压件就是一种介质。上海强田液压股份有限公司(以下简称……0元购iPhone12套餐来了,0元购Mate40套餐呢?三大电信运营商的财报显示,2020年前三季度共实现营收约10924亿元,其中中国移动实现营收5744亿元,中国电信和中国联通分别实现营收2926亿元和2254亿元,两家合计营收……被骗了!红米K40比吴亦凡还渣红米K40的手机虽然很强,性价比很高,当时也是看中了这些,忍不住在618之前就买了它。但随着我收到实机到现在过去了两个多月了,一些问题也随之而来,尤其是这几点,让我苦红米K40……拯救五音不全唱吧G1无线喇叭麦克风开箱在值得买太原分舵的一次线下聚会,吃完饭大家正琢磨着去哪儿接着浪,站内红人缘溪行神神叨叨说要给我们看看她的新玩具,然后就拿出了她粉红色的小宝贝一个话筒。话筒有什么稀罕,谁还……升级macOS10。15。4软件不兼容怎么办?软件意外退出解最新系统10。15。4部分软件无法启动,会存在闪退或崩溃的问题,怎么办?下面macw小编为大家带来升级macOS10。15。4软件不兼容解决方法。第一步安装Xcode,如……紧急情况不要怕卡儿酷应急电源帮您忙如今社会快速发展,越来越多的家庭都开上了自己家的小轿车。而大家在路上行驶的时候难免会遇到汽车抛锚打不着火的情况。如果这种事情发生在市区并且在白天的话其实也还好,但是如果它发生在……对标冠道,15万出头买大五座中型SUV,轴距近2。9米,标配七座中型SUV应该是目前最受欢迎的车型,但要是论舒适性,还是大五座更出色,在这个领域,本田冠道算是做得不错的,不过20多万买一台搭载1。5TCVT的车型,想必也跟性价比没啥联系……
你只知道vivo努比亚双屏手机?这些双屏不到半价都没人愿意买2018然年底,vivoNEX双屏版、努比亚X两款双屏手机可以说是比较热门的手机。当然,很大一部分热度是大家吐槽这是倒退的设计。vivoNEX双屏版、努比亚X两款手机虽然背面设……2021的第一个机皇三星GalaxyS215G全系解析北京时间1月14日晚11点,三星正式发布了全新一代旗舰机GalaxyS215G系列,拉开了2021年安卓机皇大战的帷幕。毫无疑问的是,每一代的GalaxyS都是上半年整个安卓阵……SpringBootMyBatisAOPLayUI实现权限管项目描述关注转发之后私信回复【源码】二字即可免费获取到项目源码学习springbootmybatis使用面向切面编程(AOP)实现的权限管理系统。共五个模块,角色管……小米首款冲击中高端的耳机小米Air2Pro?300元以内音质前言:夏日炎炎,比起头戴式降噪耳机的闷热感,TWS真无线耳机舒适度可谓倍增。现在我们来聊一聊小米真无线蓝牙耳机Air2Pro,现在已经发布了10个月左右。但相比较刚发布的……五菱又一新车,续航305km极速100kmh,两座布局或卖6不得不说,五菱近一年多时间推出的新车,比如火到出圈的宏光MINIEV,就凭借高性价比、高颜值、高代步属性,在仅一年时间里就收获了超37万用户的喜爱。后续的五菱凯捷,其大四座的特……限电令至,家居行业最贵的冬天到了吗?近期,不少制造业大省以及原材料大省,以控碳的名义,下发了能耗双控的相关政策文件,我国多地均相应出台了限电政策,要求工厂产能下降20,很多家居企业对此猝不及防,水泥、陶瓷、钢铁等……HiX再获国际大奖!日本VGP受赏公布2020年12月,日本的VGP授奖如期而至!AustrianAudioHiX55及HiX50凭借强大的实力再次斩获今年的VGP奖!关注数码产品的小伙伴一……清洁机器中的战斗机SEGOO小洁扫地机机器人科技一直在进步,我们的生活也一直在改变,在现代家居生活中扫地机器人正在被越来越多的人接受尤其是对很多忙于工作而没有时间去做家务的年轻人来说拥有一台通过远程遥控就能够帮你完成扫地……改装汽车大灯,为什么更推荐LED而不是氙气灯?行内人说了实话汽车大灯就像是汽车的眼睛,在夜间行驶以及天气不好的时候起着十分重要的作用。随着汽车技术的发展,汽车大灯经历了卤素灯、氙气灯、LED灯和激光灯几个过程。市面上在售的车型,有些出于……遭遇集体讨债,揭秘海粉宝宝背后的生态圈阴谋又一家社交电商平台被群攻了。一串曝光的聊天记录显示,一家名为海粉宝宝的社交电商平台被公开讨债,大量维权者在微信群喊话平台退钱,平台不仅没有正面回应,还在群内发表一些关于平……狼学家你根本不了解变若之子!!大家好,又是我啦文字7000,阅读时间15分钟左右,视频时间20分钟。如果你是被标题与封面吸引进来的,哈哈哈,那恭喜你了,我确实没标题党,这次真的是说变若之子的故事。……康熙为何如此恨姚启圣?恨不得杀一千次?明珠一句话道破原因姚启圣到底何许人也,康熙对其恨之入骨却无可奈何。曾为清朝立下汗马功劳,仍无法缓解康熙心中的愤恨,康熙为何不在收复台澎之后将其杀之,原来康熙在下一盘大棋,天下人皆沦为棋子。……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网