天道酬勤,学无止境

如何将 asyncio 与其他操作系统线程同步?(How can I synchronize asyncio with other OS threads?)

问题

我有一个带有一个主线程的程序,我在其中生成了第二个使用 asyncio 的线程。 是否提供了任何工具来同步这两个线程? 如果一切都是异步的,我可以使用它的同步原语来做到这一点,例如:

import asyncio

async def taskA(lst, evt):
    print(f'Appending 1')
    lst.append(1)
    evt.set()

async def taskB(lst, evt):
    await evt.wait()
    print('Retrieved:', lst.pop())

lst = []
evt = asyncio.Event()
asyncio.get_event_loop().run_until_complete(asyncio.gather(
    taskA(lst, evt),
    taskB(lst, evt),
))

但是,这不适用于多线程。 如果我只使用threading.Event那么它将阻塞 asyncio 线程。 我发现我可以将等待推迟到执行人:

import asyncio
import threading

def taskA(lst, evt):
    print(f'Appending 1')
    lst.append(1)
    evt.set()

async def taskB(lst, evt):
    asyncio.get_event_loop().run_in_executor(None, evt.wait)
    print('Retrieved:', lst.pop())

def targetA(lst, evt):
    taskA(lst, evt)

def targetB(lst, evt):
    asyncio.set_event_loop(asyncio.new_event_loop())
    asyncio.get_event_loop().run_until_complete(taskB(lst, evt))

lst = []
evt = threading.Event()
threadA = threading.Thread(target=targetA, args=(lst, evt))
threadB = threading.Thread(target=targetB, args=(lst, evt))
threadA.start()
threadB.start()
threadA.join()
threadB.join()

然而,让一个执行线程只等待一个互斥锁似乎是不自然的。 这是应该这样做的方式吗? 或者有没有其他方法可以异步等待操作系统线程之间的同步?

回答1

将 asyncio 协程与来自另一个线程的事件同步的一种简单方法是在 taskB 中等待asyncio.Event ,并使用loop.call_soon_threadsafe从 taskA 设置它。

为了能够在两者之间传递值和异常,可以使用期货; 但是,您正在发明很多run_in_executor 。 如果 taskA 的唯一工作是从队列中取出任务,那么您不妨创建一个单工作“池”并将其用作工作线程。 然后您可以按预期使用run_in_executor

worker = concurrent.futures.ThreadPoolExecutor(max_workers=1)

async def taskB(lst):
    loop = asyncio.get_event_loop()
    # or result = await ..., if taskA has a useful return value
    # This will also propagate exceptions raised by taskA
    await loop.run_in_executor(worker, taskA, lst)
    print('Retrieved:', lst.pop())

语义与具有显式队列的版本相同 - 队列仍然存在,它就在ThreadPoolExecutor内部。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何在异步协程中包装同步函数?(How can I wrap a synchronous function in an async coroutine?)
    问题 我正在使用 aiohttp 构建一个 API 服务器,该服务器将 TCP 请求发送到单独的服务器。 发送 TCP 请求的模块是同步的,我的目的是一个黑盒子。 所以我的问题是这些请求阻塞了整个 API。 我需要一种方法将模块请求包装在异步协程中,该协程不会阻塞 API 的其余部分。 所以,仅以sleep作为一个简单的例子,有没有办法以某种方式将耗时的同步代码包装在非阻塞协程中,如下所示: async def sleep_async(delay): # After calling sleep, loop should be released until sleep is done yield sleep(delay) return 'I slept asynchronously' 回答1 最终我在这个线程中找到了答案。 我正在寻找的方法是 run_in_executor。 这允许同步函数异步运行而不会阻塞事件循环。 在我上面发布的sleep示例中,它可能如下所示: import asyncio from time import sleep async def sleep_async(loop, delay): # None uses the default executor (ThreadPoolExecutor) await loop.run_in_executor(None
  • 循环运行时,如何运行协程并等待同步函数的结果?(How to run a coroutine and wait it result from a sync func when the loop is running?)
    问题 我有一个像傻瓜一样的代码: def render(): loop = asyncio.get_event_loop() async def test(): await asyncio.sleep(2) print("hi") return 200 if loop.is_running(): result = asyncio.ensure_future(test()) else: result = loop.run_until_complete(test()) 当loop没有运行时很容易,只需使用loop.run_until_complete并返回 coro 结果,但如果循环已经在运行(我的阻塞代码在已经运行循环的应用程序中运行)我不能使用loop.run_until_complete因为它会引发异常; 当我调用asyncio.ensure_future ,任务被安排并运行,但我想在那里等待结果,有人知道怎么做吗? 文档不是很清楚如何做到这一点。 我尝试在 coro 内部传递一个concurrent.futures.Future调用set_result ,然后在我的阻塞代码上调用Future.result() ,但它不起作用,它阻塞在那里并且不让其他任何东西运行。 任何帮助,将不胜感激。 回答1 为了实现runner与所提出的设计,你需要一种方法来单步从里面运行的回调事件循环。
  • asyncio 模块是如何工作的,为什么我更新的示例是同步运行的?(How does the asyncio module work, why is my updated sample running synchronously?)
    问题 我在 Python 3.6 中为 asyncio 尝试了以下代码:示例 1: import asyncio import time async def hello(): print('hello') await asyncio.sleep(1) print('hello again') tasks=[hello(),hello()] loop=asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) 输出符合预期: hello hello hello again hello again 然后我想把 asyncio.sleep 改成另一个 def: async def sleep(): time.sleep(1) async def hello(): print('hello') await sleep() print('hello again') tasks=[hello(),hello()] loop=asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) 输出: hello hello again hello hello again 它似乎不是在异步模式下运行,而是在正常同步模式下运行。 问题是
  • asyncio 模块是如何工作的,为什么我更新的样本是同步运行的?(How does the asyncio module work, why is my updated sample running synchronously?)
    问题 我在 Python 3.6 中为 asyncio 尝试了以下代码:示例 1: import asyncio import time async def hello(): print('hello') await asyncio.sleep(1) print('hello again') tasks=[hello(),hello()] loop=asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) 输出如预期: hello hello hello again hello again 然后我想把 asyncio.sleep 改成另一个 def: async def sleep(): time.sleep(1) async def hello(): print('hello') await sleep() print('hello again') tasks=[hello(),hello()] loop=asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) 输出: hello hello again hello hello again 它似乎不是在异步模式下运行,而是在正常同步模式下运行。 问题是
  • Django 是同步的还是异步的?(Django is synchronous or asynchronous?)
    问题 Django 是同步的还是异步的? 我想知道Django框架是同步的还是异步的。 我听说过他们询问您使用的框架是同步还是异步的面试问题。 所以我想知道同步和异步在web开发方面的含义。 回答1 Django 本身是同步的。 每个 HTTP 请求都将完全同步处理。 但是,您有像 django-channels ( https://github.com/django/channels ) 这样的扩展,它们是异步的,用于网络套接字等。 这有点过于简化了:但是同步编程是如果您编写代码,从头到尾处理一个 HTTP 请求,并且在一个线程或一个进程中执行,并且一个进程/一个线程一次仅处理一个请求。 使用python,特别是asyncio 或twisted 可以编写这样的代码,即一个进程/线程可以处理多个请求。 每当一个请求等待接收网络上的新数据或发送一大块数据时,它就可以处理另一个请求,直到其他请求等待网络准备就绪。 Django 版本 < 3.0 但是不使用twisted 或asyncio,因此http 请求仅以同步方式处理。 然而,新的网络服务器/网络应用程序不仅可以处理 http 请求,还可以使用网络套接字。 Django 通道模块是为处理 Web 套接字而构建的。 它是用 asyncio 实现的,它允许只用一个进程处理多个 web 套接字。 它将通过消息(例如 redis)与
  • Python 3.5 async/await 与真实代码示例(Python 3.5 async/await with real code example)
    问题 我已经阅读了大量关于 Python 3.5 async/await 的文章和教程。 我不得不说我很困惑,因为有些使用 get_event_loop() 和 run_until_complete(),有些使用 ensure_future(),有些使用 asyncio.wait(),有些使用 call_soon()。 看起来我有很多选择,但我不知道它们是否完全相同,或者在某些情况下您使用循环并且有些情况下您使用 wait()。 但事情是所有的例子都使用asyncio.sleep()作为模拟真正的慢操作,它返回一个可等待的对象。 一旦我尝试将这一行换成一些真实的代码,整个事情就会失败。 上面写的方法之间到底有什么区别,我应该如何运行尚未准备好进行 async/await 的第三方库。 我确实使用 Quandl 服务来获取一些股票数据。 import asyncio import quandl async def slow_operation(n): # await asyncio.sleep(1) # Works because it's await ready. await quandl.Dataset(n) # Doesn't work because it's not await ready. async def main(): await asyncio.wait([
  • 同步睡眠进入 asyncio 协程(Synchronous sleep into asyncio coroutine)
    问题 我有一个协程如下: async def download(): downloader = DataManager() downloader.download() DataManager.download()方法如下所示: def download(self): start_multiple_docker_containers() while True: check_containers_statuses() sleep(N) # synchronous sleep from time module 这是一个好习惯吗? 如果不是,我如何在download()使用asyncio.sleep ? 或者这种代码结构在概念上是错误的? 回答1 这是我的解决方案: import asyncio import time # Mocks of domain-specific functions # ---------------------------------- def get_container_status(container_id, initial_time): """This mocks container status to change to 'exited' in 10 seconds""" if time.time() - initial_time < 10: print
  • 如何等待从另一个线程提交的回调完成?(How can you wait for completion of a callback submitted from another thread?)
    问题 我有两个共享某个状态的 Python 线程A和B 。 有一次, A提交了一个回调以供B在其循环中运行,例如: # This line is executed by A loop.call_soon_threadsafe(callback) 在此之后,我想继续做其他事情,但我想确保在执行此操作之前callback已由B运行。 有没有办法(除了标准线程同步原语)让A等待回调完成? 我知道call_soon_threadsafe返回一个可以取消任务的asyncio.Handle对象,但我不确定这是否可以用于等待(我仍然不太了解asyncio )。 在这种情况下,这个回调调用loop.close()并取消剩余的任务,然后在B ,在loop.run_forever()有一个loop.close() 。 因此,对于这个用例,特别是允许我从A知道循环何时有效关闭的线程安全机制也适用于我 - 同样,不涉及互斥锁/条件变量/等。 我知道asyncio并不是线程安全的,只有很少的例外,但我想知道是否提供了一种方便的方法来实现这一点。 这是我的意思的一小部分,以防万一。 import asyncio import threading import time def thread_A(): print('Thread A') loop = asyncio.new_event_loop()
  • [进阶]-Python3 异步编程详解(史上最全篇)
    目录 1 什么是异步编程 1.1 阻塞 1.2 非阻塞 1.3 同步 1.4 异步 1.5 并发 1.6 并行 1.7 概念总结 1.8 异步编程 1.9 异步之难(nán) 2 苦心异步为哪般 2.1 CPU的时间观 2.2 面临的问题 2.3 解决方案 3 异步I/O进化之路 3.1 同步阻塞方式 3.2 改进方式:多进程 3.3 继续改进:多线程 3.4 非阻塞方式 3.5 非阻塞改进 3.5.1 epoll 3.5.2 回调(Callback) 3.5.3 事件循环(Event Loop) 3.5.4 总结 4 Python 对异步I/O的优化之路 4.1 回调之痛,以终为始 4.2 核心问题 4.3 协程 4.4 基于生成器的协程 4.4.1 未来对象(Future) 4.4.2 重构 Crawler 4.4.3 任务对象(Task) 4.4.4 事件循环(Event Loop)驱动协程运行 4.4.5 生成器协程风格和回调风格对比总结 4.4.6 碉堡了,但是代码很丑!能不能重构? 4.5 用 yield from 改进生成器协程 4.5.1 yield from语法介绍 4.5.2 重构代码 4.5.3 yield from改进协程总结 4.5.4 asyncio 介绍 4.6 总结 5 asyncio和原生协程初体验 结语 1 什么是异步编程 1.1 阻塞
  • python中的异步编程(asynchronous programming in python)
    问题 在python中有异步编程的一般概念吗? 我可以为函数分配一个回调,执行该回调并立即返回主程序流程,无论该函数执行需要多长时间? 回答1 在这里看看: Python异步编程 异步编程和扭曲简介 值得一试: asyncio(以前为Tulip)已被检入Python默认分支 于2018年3月14日编辑 如今,Python具有asyncIO-内置的异步I / O,事件循环,协程和任务。 描述来自上面的链接: asyncIO模块提供了用于使用协程编写单线程并发代码,通过套接字和其他资源对I / O进行多路访问,运行网络客户端和服务器以及其他相关原语的基础结构。 这是软件包内容的更详细列表: 具有各种特定于系统的实现的可插入事件循环; 传输和协议抽象(类似于Twisted中的抽象); 对TCP,UDP,SSL,子进程管道,延迟的调用等(具体取决于系统)的具体支持; 一个Future类,它模仿并发模块中的那个,但是适合与事件循环一起使用; 基于(PEP 380)的收益的协程和任务,以帮助以顺序方式编写并发代码; 取消对期货和协程的支持; 用于在单个线程中的协程之间使用的同步原语,模仿线程模块中的同步原语; 一个将工作传递给线程池的接口,在您绝对必须使用肯定会使用阻止阻塞的I / O调用的库的时候。 异步编程比经典的“顺序”编程更为复杂:请参见“使用异步开发”页面
  • 如何在事件循环中将协程打包为普通函数?(How can I package a coroutine as normal function in event loop?)
    问题 我正在将asyncio用于网络框架。 在下面的代码中( low_level是我们的低级函数, main块是我们的程序入口, user_func是用户定义的函数): import asyncio loop = asyncio.get_event_loop() """:type :asyncio.AbstractEventLoop""" def low_level(): yield from asyncio.sleep(2) def user_func(): yield from low_level() if __name__ == '__main__': co = user_func() loop.run_until_complete(co) 我想将low_level包装为普通函数,而不是coroutine (出于compatibility等原因),但是low_level在事件循环中。 如何将其包装为正常功能? 回答1 由于low_level是协程,因此只能通过运行asyncio事件循环来使用。 如果您希望能够从未运行事件循环的同步代码中调用它,则必须提供一个包装器,该包装器实际上会启动事件循环并运行协程直到完成: def sync_low_level(): loop = asyncio.get_event_loop() loop.run_until_complete(low
  • 异步实际上是如何工作的?(How does asyncio actually work?)
    问题 这个问题是由我的另一个问题引起的:如何在cdef中等待? Web上有asyncio关于asyncio的文章和博客文章,但是它们都是非常肤浅的。 我找不到任何关于如何的任何信息asyncio实际上是实现,是什么使I / O异步的。 我正在尝试阅读源代码,但是它是数千行,不是最高等级的C代码,其中很多处理辅助对象,但是最关键的是,很难在Python语法和它将翻译的C代码之间建立联系。进入。 Asycnio自己的文档甚至没有多大帮助。 那里没有关于它如何工作的信息,只有一些有关如何使用它的指南,有时也会引起误解/写得很差。 我熟悉Go的协程实现,并希望Python能够完成同样的事情。 如果是这样的话,我在上面链接的帖子中出现的代码将奏效。 既然没有,我现在想找出原因。 到目前为止,我最好的猜测如下,请纠正我错的地方: 形式为async def foo(): ...过程定义实际上被解释为继承coroutine的类的方法。 也许, async def实际上是通过await语句分为多个方法的,在这些方法中,调用这些方法的对象能够跟踪到目前为止执行所取得的进展。 如果上述条件成立,那么从本质上讲,协程的执行可以归结为某些全局管理器调用循环对象的方法(循环?)。 全局管理器以某种方式(如何?)知道何时由Python代码执行I / O操作(仅?),并且能够在当前执行方法放弃控制(
  • 如何将python asyncio与线程结合在一起?(How to combine python asyncio with threads?)
    问题 我已经使用Python asyncio和aiohttp成功构建了一个RESTful微服务,该服务可侦听POST事件以收集来自各种供料器的实时事件。 然后,它构建一个内存结构,以将事件的最后24小时缓存在嵌套的defaultdict / deque结构中。 现在,我想定期检查该结构到磁盘的位置,最好使用pickle。 由于内存结构可以大于100MB,因此我想避免在检查点结构所花的时间上占用我的传入事件处理。 我宁愿为该结构创建快照副本(例如,Deepcopy),然后花点时间将其写入磁盘,并在预设的时间间隔内重复执行。 我一直在寻找有关如何组合线程的示例(线程是否是为此的最佳解决方案?)和异步用于此目的,但是找不到对我有帮助的东西。 任何入门的指针都将不胜感激! 回答1 使用BaseEventLoop.run_in_executor将方法委托给线程或子进程非常简单: import asyncio import time from concurrent.futures import ProcessPoolExecutor def cpu_bound_operation(x): time.sleep(x) # This is some operation that is CPU-bound @asyncio.coroutine def main(): # Run cpu_bound
  • Tulip/asyncIO:为什么不是所有调用都是异步的并指定何时应该同步?(Tulip/asyncIO: why not all calls be async and specify when things should be synchronous?)
    问题 当 Guido 谈到 Tulip 时,我参加了 SF Python 聚会,Tulip,未来用于 Python 异步操作的 asyncIO 库。 需要注意的是,如果您想要异步运行某些东西,您可以使用"yield from" + expression和几个装饰器来指定应异步执行对yield from之后的内容的调用。 关于它的好处是您可以正常读取该函数中的语句(就像它是同步的一样),并且它的行为就好像它在该函数的执行(返回值和错误/异常传播和处理)方面是同步的)。 我的问题是:为什么不具有相反的行为,即默认情况下所有函数调用都是异步的(并且没有yield from ),并且当您想要同步执行某些操作时具有不同的显式语法? (除了需要另一个关键字/语法规范) 回答1 真正的答案是 Guido喜欢在协程中异步让出点是明确的这一事实,因为如果您没有意识到调用可以让出,那么这就是并发问题的邀请——就像线程一样。 但是,如果您必须从 编写显式yield from ,则很容易确保它不会落在两个对其余代码来说应该是原子的关键操作的中间。 正如他在 PyCon 2013 主题演讲中提到的,还有其他 Python 异步框架,例如 Gevent,默认情况下是异步的,他不喜欢这种方法。 (在 11:58): 不幸的是,您仍然没有完全清楚调度程序可能会在随机时刻中断您的任务并切换到另一个任务的问题。 [
  • 在线程 + 队列或 ThreadPoolExecutor 上使用异步等待?(Using async-await over Thread + Queue or ThreadPoolExecutor?)
    问题 我从未使用过async-await语法,但我确实经常需要在等待未来响应的同时发出 HTTP/S 请求并解析响应。 为了完成这个任务,我目前使用 ThreadPoolExecutor 类,它无论如何都异步执行调用; 实际上,我正在实现(我相信)与使用更多代码行使用async-await得到的结果相同的结果。 假设我当前的实现是异步工作的,我想知道async-await实现与我原来使用线程和队列来管理工作线程的实现有何不同; 它还使用信号量来限制工人。 该实现是在以下条件下设计的: 可能有任意数量的请求活动请求的总数可能是 4 仅在收到响应时发送下一个请求 实现的基本流程如下: 生成请求容器创建一个监听队列为每个请求创建一个线程并传递 URL、ListeningQueue 和信号量每个线程尝试获取信号量(限制为 4 个线程) 主线程继续在while检查ListeningQueue 当一个线程收到响应时,放入 ListeningQueue 并释放 Semaphore 等待线程获取信号量(过程重复) 主线程处理响应直到计数等于请求数 因为我需要限制活动线程的数量,所以我使用信号量,如果我要使用async-await来尝试这个,我将不得不在主线程或async def设计一些逻辑来防止请求被发送,如果已达到限制。 除了这个限制之外,我看不出在哪里使用async-await会更有用。
  • 同步在Java中如何工作?(How Synchronization works in Java?)
    问题 我对Java同步有疑问。 我想知道我的类中是否有三个同步方法,并且一个线程在一个同步方法中获得了锁,另外两个将被锁定吗? 我问这个问题是因为我对以下陈述感到困惑。 当线程处于对象的同步方法中时,希望执行该同步方法或对象的任何其他同步方法的所有其他线程将必须等待。 此限制不适用于已经具有锁并正在执行对象的同步方法的线程。 这样的方法可以调用对象的其他同步方法而不会被阻塞。 当然,任何线程都可以随时调用对象的非同步方法 回答1 Java中的同步是通过在某些特定对象上获取监视器来完成的。 因此,如果您这样做: class TestClass { SomeClass someVariable; public void myMethod () { synchronized (someVariable) { ... } } public void myOtherMethod() { synchronized (someVariable) { ... } } } 然后,在不修改someVariable情况下,可以随时通过执行2个不同的线程来保护这两个块。 基本上,据说这两个块是与变量someVariable同步的。 当您在方法上设置synchronized时,它的含义基本上与synchronized (this)相同,即在执行此方法的对象上进行同步。 那是: public
  • Python 异步 async/await
    文章目录 CPU的时间观I/O(异步的瓶颈)基础概念进程/线程阻塞/非阻塞并发/并行CPU调度策略 同步/异步事件循环+回调 协程(异步)async/awaitasyncio事件循环(python3.6)asyncio事件循环(python3.7)asyncawaitasyncio.create_task()asyncio.futures对象 实例参考 介绍异步前,先简述几个计算中有意思的概念。 CPU的时间观 如果电脑的主频为2.6G,也就是每秒可以执行2.6*10^9个指令,每个指令只需要0.38ns。 假设一个指令时间比作人类能够感知的一秒钟来对比数据,如下图: (借用一张网络download的CPU时间观的对比图) 举个常见的例子 1Gbps网络上传输2KB数据,真实延迟20微秒,CPU感觉过了14.4小时!!! CPU是计算机的核心,如果利用率低,不仅浪费资源,而且程序执行效率低下,需要耗费更长的时间(这是最应该关注的点)如果不提高程序执行效率,等同于“谋财害命” I/O(异步的瓶颈) CPU的时间观中可以看出除了执行指令和一级缓存,对CPU来说是可接受的,其他操作都很慢很慢很慢很慢很慢很慢(特别是从上下文切换开始)!!!回顾一下大学期间,被老师强调无数次的的冯·诺依曼结构数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑
  • 一则故事表达:并发,并行,同步,异步,线程,多线程
    一个小事件说明下并发,并行,同步,异步,线程,多线程 一个广交会举办向8间公司发起展览邀请, 参展公司有8间,场地有80万平方米的展示区域, 每个参展商有10万平方米可以用于展出售卖, 每个参展公司仅仅配备1个员工,每个货架之间都有距离, 员工在销售时需要去到货架前面,每个货架仅能放一种商品。 8间公司的摊位:多进程 8间公司都在售卖中:并行 第1间公司有1个货架,货架有1个商品:1线程 第2间公司有20个货架,每个货架有1个商品:20线程 第3间公司有1个货架,货架配置100件商品:单线程并发(异步) 第4间公司有没有货架,卖的【按摩服务】。 第5间公司与第6间公司是同一个母公司,名为A公司,也就意味着A公司有2个摊位:并行 对应理解 【并发】:广交会举办向8间公司发起展览邀请,分先后,先发邀请函给我之后再发给你......一共发了8个邀请 【多进程】:8间公司的都有自己的摊位 【并行】:8间公司同时进行着展示任务,每一间公司都有属于自己的摊位,不用和别人轮流共用一个摊位 【线程】:货架的数量 【计算密集型】:第1间参展公司有1个货架配置1个商品,卖的是大型商品【大核弹头】,需要详细讲解使用方法才能使用的商品。 【处理I/O密集型】:第3间公司有1个货架,配置100件商品,卖的是小型商品【纯净水】,直接收钱交货,讲解的内容少。 【同步】:第4间公司,卖的是【按摩服务】
  • 网络与并发之多线程与多进程
    Python-网络与并发 第五章 多线程与多进程 ​ 现代操作系统比如 Mac OS X,Linux,Windows 等,都是支持“多任务”的操作系统什 么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用 逛淘宝,一边在听音乐,一边在用微信聊天,这就是多任务,至少同时有 3 个任务正在运行。 ​ 还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。现在,多核 CPU 已经非常普及了,但是,即使过去的单核 CPU,也可以执行多任务。由 于 CPU 执行代码都是顺序执行的,那么,单核 CPU 是怎么执行多任务的呢? ​ 我们知道,在一台计算机中,我们可以同时打开许多软件,比如同时浏览网页、听音乐、打字等等,看似非常正常。但仔细想想,为什么计算机可以做到这么多软件同时运行呢?这就涉及到计算机中的两个重要概念:多进程和多线程了。 进程和线程都是操作系统中的重要概念,既相似,又不同 对于一般的程序,可能会包含若干进程;而每一个进程又可能包含多个同时执行的线程。进程是资源管理的最小单位,而线程则是程序执行的最小单位。 1. 进程和线程的概念 ​ 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动 一个浏览器进程,就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开 一个 Word 就启动了一个 Word
  • synchronized 关键字如何在内部工作(how synchronized keyword works internally)
    问题 我阅读了下面的程序并在博客中回答。 int x = 0; boolean bExit = false; 线程 1(未同步) x = 1; bExit = true; 线程 2(未同步) if (bExit == true) System.out.println("x=" + x); 线程 2 是否可以打印“ x=0 ”? 答:是(原因:每个线程都有自己的变量副本。) 你怎么解决? Ans :通过使用使两个线程在公共互斥锁上同步或使两个变量都可变。 我的疑问是:如果我们将 2 变量设为 volatile,那么 2 个线程将共享主内存中的变量。 这是有道理的,但在同步的情况下,它将如何解决,因为两个线程都有自己的变量副本。 请帮我。 回答1 这实际上比看起来更复杂。 有几件神秘的事情在起作用。 缓存 说“每个线程都有自己的变量副本”并不完全正确。 每个线程都可能有自己的变量副本,它们可能会也可能不会将这些变量刷新到共享内存中和/或从那里读取它们,因此整个事情是不确定的。 此外,术语刷新实际上是依赖于实现的。 有严格的术语,例如内存一致性、先发生顺序和同步顺序。 重新排序 这个就更玄了。 这 x = 1; bExit = true; 甚至不保证线程1将首先写1到x ,然后true到bExit 。 事实上,它甚至不能保证任何这些都会发生。 如果稍后不使用它们,编译器可能会优化掉一些值