文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Python并发处理

2023-01-31 02:12

关注

1.创建并销毁线程

#!/usr/bin/python

#code to execute in an independent thread

import time
def countdown(n):
    while n > 0:
       print('T-minus',n)
       n -= 1
       time.sleep(5)

#create and launch a thread

from threading import Thread
t = Thread(target=countdown,args=(10,))
t.start()



# python concurency.py 
('T-minus', 10)
('T-minus', 9)
('T-minus', 8)
('T-minus', 7)
('T-minus', 6)
('T-minus', 5)
('T-minus', 4)
('T-minus', 3)
('T-minus', 2)
('T-minus', 1)



创建一个线程实例后,需要调用start()让其运行。线程是以系统级别线程的方式执行,由操作系统管理。一旦执行,各个线程独立运行,直到目标函数返回结果,可以使用is_alive()查询一个线程实例是否正在运行。

if t.is_alive():
   print('The thread is still running')
else:
   print('Completed')



可以使用join()来请求结合一个线程



执行上述代码时,python解释器会等待所有线程结束。对于需要时间较长的线程或者后台任务,可以考虑将线程以daemon的方式运行


t.setDaemon(True)


不能结合以daemon方式运行的线程,当主线程终止时它们会自动销毁



如果想要能够终止线程,这些线程必须能够可编程在选择的点上能够退出

import time
from threading import Thread

class CountdownTask:
     def __init__(self):
         self._running=True

     def terminate(self):
         self._running=False

     def run(self,n):
         while self._running and n > 0:
             print('T-minus',n)
             n-=1
             time.sleep(5)

c=CountdownTask()
t=Thread(target=c.run,args=(10,))
t.start()

c.terminate()
t.join()


由于Global Interpreter Lock(GIL)全局解释器锁的原因,Python线程被限制在任何给定时间内只能有一个线程可以执行。基于这个原因,Python线程不能用于那些需要大量计算的任务。Python线程更适合用于I/O处理,处理那些执行阻塞操作例如等待I/O,等待数据库操作结果等的代码的并发执行。




2.判断一个线程是否已经启动

Problem:

已经启动一个线程,但是想要知道它什么时候开始运行的


Solution:

Python线程的一个关键特性就是它们独立执行并且非确定性。如果程序的其他线程需要知道是否一个线程执行进一步操作之前已经达到某一个阶段。threading模块的Event对象可以帮助解决这个问题‘

#!/usr/bin/python

from threading import Thread,Event
import time

#code to execute in an independent thread

def countdown(n,started_evt):
    print('countdown starting')
    started_evt.set()
    while n > 0:
       print('T-minus',n)
       n -= 1
       time.sleep(5)
#create the event object that will be used  to signal startup
started_evt = Event()

#launch the thread and pass the startup event
print('launching countdown')
t=Thread(target=countdown,args=(10,started_evt))
t.start()

#wait for the thread to start
started_evt.wait()
print('countdown is running')



Event objects are best used for one-time events.





#!/usr/bin/python

import threading
import time

class PerodicTimer:
    def __init__(self,interval):
        self._interval=interval
        self._flag=0
        self._cv=threading.Condition()

    def start(self):
        t=threading.Thread(target=self.run)
        t.daemon=True
        t.start()

    def run(self):
        '''
          Run the timer and notify waiting threads after each interval
        '''
        while True:
           time.sleep(self._interval)
           with self._cv:
                self._flag ^= 1
                self._cv.notify_all()


    def wait_for_tick(self):
        '''
          wait for the next tick of the timer
        '''
        with self._cv:
             last_flag=self._flag
             while last_flag == self._flag:
                self._cv.wait()
#example use of the timer
ptimer=PerodicTimer(5)
ptimer.start()

#two threads that synchronize on the timer

def countdown(nticks):
    while nticks > 0:
          ptimer.wait_for_tick()
          print('T-minus',nticks)
          nticks-=1

def countup(last):
    n=0
    while n < last:
       ptimer.wait_for_tick()
       print('Counting',n)
       n+=1

threading.Thread(target=countdown,args=(10,)).start()
threading.Thread(target=countup,args=(5,)).start()
# python event2.py 
('Counting', 0)
('T-minus', 10)
('T-minus', 9)
('Counting', 1)
('Counting', 2)
('T-minus', 8)
('Counting', 3)
('T-minus', 7)
('Counting', 4('T-minus', 6)
)
('T-minus', 5)
('T-minus', 4)
('T-minus', 3)
('T-minus', 2)
('T-minus', 1)







Event对象的一个很重要的特性就是它们会唤醒所有正在等待的线程。如果想要编写一个程序只唤醒单个正在等待的线程,更好使用Semaphore或者Condition对象

#!/usr/bin/python

import threading

#worker thread
def worker(n,sema):
    #wait to be signaled
    sema.acquire()
    #do some work
    print('working',n)
    
#create some threads
sema=threading.Semaphore(0)
nworkers=10
for n in range(nworkers):
    t=threading.Thread(target=worker,args=(n,sema,))
    t.start()


如果运行这个程序,一组线程会被启动,但是没有任何事情发生。应为它们都被阻塞等待获取信号量。每次释放信号量,只有一个worker将被唤醒和运行


直接在python终端执行将无任何反应并且无法终止程序

# python semaphore.py 
^C^C^C^C^C^C^C


在ipython终端中输入以上程序然后执行

In [8]: sema.release()

In [9]: ('working', 0)


In [9]: sema.release()

In [10]: ('working', 1)


In [10]: sema.release()
('working', 2)
 
In [11]: sema.release()
('working'
, 3)
In [12]: sema.release()
('working', 4)

In [13]: sema.release()
('working', 5)

In [14]: sema.release()
('working', 6)
 
In [15]: sema.release()

In [16]: ('working', 7)


In [16]: sema.release()

In [17]: ('working', 8)


In [17]: sema.release()
('working', 
9)
In [18]: sema.release()

In [19]: sema.release()



3.线程间通信

Problem:

执行程序时开启了多个线程,现在需要在这些线程之间通信或者交换数据

Solution:

也许从一个线程发送数据到另一个线程的最安全的方式就是使用 Queue模块.可以创建一个 Queue实例用于所有的线程共享。这些线程然后使用put()或者get()操作来向队列中添加或者删除项目

#!/usr/bin/python
from threading import Thread
from Queue import Queue

#a thread that produces data
def producer(out_q):
   while True:
      #produce some data
      data="producer data"
      out_q.put(data)


#a thread that comsumes data
def consumer(in_q):
   while True:
      #get some data
      data=in_q.get()
      #process the data
      print data
      print "consumer"

#create the shared queue and launch both threads
q=Queue()
t1=Thread(target=consumer,args=(q,))
t2=Thread(target=producer,args=(q,))
t1.start()
t2.start()


执行结果:

producer data
consumer
producer data
consumer
producer data
consumer
producer data
consumer
producer data
consumer
producer data
consumer
producer data
consumer
producer data
consumer
.......
.......


以上代码会不断地循环执行。当使用队列时,协调关闭producer和comsumer会比较诡异。









参考文章:

http://chimera.labs.oreilly.com/books/1230000000393/ch12.html


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯