php 并发代码同步代码_关于并发的代码片段

php 并发代码同步代码

在一个公司,尝试很难得到的东西以正确的方式完成工作,它只是悲哀地有时会发现一些在这篇文章中我们的代码库共享代码。 我们实际上是在尝试纠正以下一些问题,因此我从并发开始,为新人们( 总是有新人们 )分享这一点。 即使这些示例都是基于Java的,但完全相同的想法也适用于您选择的编程语言。

以下代码示例仅是为了说明问题,我们的生产代码也有类似的一般问题。

假设我们要从URL下载内容。 我们可以简单地使用以下功能。 此代码同步运行。

下面的功能可以用具有同步执行功能的其他任何东西代替,例如访问数据库或将某些内容保存到文件系统。 基于此,可悲的是,在我们的代码库中发现了以下内容。

如我们所见,这确实是下载内容的非常糟糕的方式。 它绝对不会异步执行任何操作。 当我们查看函数getContenAsyncBadWay的签名时,甚至更糟,因为所有人都表明它将异步运行。

通过执行以下代码,我们可以验证它是否正在串行运行。

输出将是。

hello
...
done
waiting

正如我们所观察到的,即使我们不认为,所有事情都是线性发生的。

我们正在尝试训练我们的一些资源(人员)不要这样做,而写以下内容。

我们正在努力避免这些愚蠢的错误。

请注意,我们都包裹.getContent内部通话supplyAsync 。 我们可以通过执行与之前类似的代码来再次对其进行测试。

哪个可以正确输出我们的期望。

hello
waiting
...
done

请注意输出中的顺序,它确实表明一切正常。

早期阻止和链接

我们在代码库中发现的另一个问题是,我们阻塞了异步操作以访问其结果,在大多数情况下,这是完全不必要的。

以下示例显示了我们遇到的相同问题。

这非常糟糕,因为您可以认为操作正在异步进行,但这并不比 以同步方式 调用 .getContent 更好 ,因为我们在调用之后立即阻塞。

其结果将是。

hello
!=293
"=25
#=406
$=33
&=5
'=79
(=21
)=117
*=117
...
waiting

同样,此代码被CompletableStage污染,即使使用正确的实现.getContentAsyncBetterWay ,它也仍然非常同步。

相反,我们应该执行以下操作。

注意我们如何将计算阶段链接到.countWords ,然后打印结果。

运行此版本将为我们提供以下内容。

hello
waiting
!=293
"=25
#=406
$=33
&=5
'=79
(=21
)=117
*=117
+=1
,=24
...

再一次注意输出顺序,该顺序指示事物的运行方式。

由于某些原因,有些人很难理解这些概念。

有时您绝对需要结果

为了继续我们的示例,让我们添加以下支持功能。

现在,我们可以运行先前示例的修改版本。

在这里,尽管我们.join ING,我们正在推迟,直到快结束的时候,所以我们允许其他操作执行, AsyncOps.sumAsync在这种情况下。 该程序的输出将是。

hello
waiting
Summing -1974445143 + -1585876417
!=293
"=25
#=406
$=33
&=5
'=79
(=21
)=117
*=117
...

但是,使用同一程序的以下版本,我们仍然可以做得更好。

在这种情况下, .forEach将在计算值之后发生, .join将等待它。 看起来似乎相同,但要考虑很大的计算值。 在第一个版本中,只有在打印(或处理)之前,什么都不会执行。 在此版本中,对计算值的处理实际上是异步运行的。

多个异步操作正在运行

在许多情况下,我们需要同时运行两个或多个异步操作,并且在许多情况下它们彼此独立。 由于我们的代码库受到.join污染,因此我们无法在应有的情况下处理多处理问题,因此请编写类似以下内容的代码。

不要加入.join很重要,因为在大多数情况下,我们希望在此之后运行其他操作。 如果这些操作是同步的,则使用CompletionStage提供的单子操作。 如果操作是不同的,独立的计算,则对第一个进行阻塞将阻止第二个运行,这会大大降低性能。

尝试使用Async / Await编写更好的并发代码

这是C#和.NET多年来使用的范例,由于大多数代码看起来非常串行,因此减少了考虑并发的时间。 但是,该模型在大多数情况下提高了速度,同时增加了所执行操作的清晰度。

让我们看一个示例,它可以帮助我们了解其工作原理。

假设我们要运行执行以下操作的异步操作:

  1. 从URL下载内容
  2. 打印内容
  3. 计算一个字符出现在下载内容中的次数。
  4. 打印柜台
  5. 归还柜台

首先,让我们看看如何使用经典的Java Async API来完成此操作。

我们可能会争辩说这已经足够好了,但是还有另一种使用异步等待的方法胜过这种方法。

很少注意的事情。 首先,此功能是完全异步的,内部没有任何阻塞。 其次,对await的函数调用将控制流返回给函数getContentTotalSizeFor的调用者,直到完成等待函数为止。 每次此函数等待其依赖项工作完成时,这将允许执行更多工作。 而且,该代码非常易于理解和编写,并且不需要考虑它。

我们可以使用以下方法进行测试。

输出将是。

hello
waiting
...
59

请注意,即使在getContentTotalSizeFor内部await ,它也不会阻塞。 第一次单击await ,控件返回到调用方(在本例中为main),因此它将继续执行工作( System.out.println("waiting"); )。 一旦函数等待结束, getContentTotalSizeFor将从其所在位置继续执行。

让我们回过头来,在代码上放一些数字以跟踪执行情况。

请注意,每次await都完成后,从该点开始恢复控制。 如果找到一个新的await ,控件将返回到调用方。 同时,所有这些都是异步的,并且不会阻止调用方函数的工作。

在编译时, async/await代码被转换为类似的字节代码,就像我们在第一个示例中编写常规CompletableFuture代码一样。

如果您现在还不确定,那么让我们看一些更有趣的例子。

要么

下面是一个更复杂的示例。

或者我们可以将其编写如下。

请注意, squarescubes的计算是两个独立的计算,它们是同时异步运行的。

结论

首先,我们需要充分了解代码库中当前存在的问题,以便我们与编写该代码的人员一起工作并解决问题。 这会影响不同级别的性能。

另外,对于那些不熟悉并发的人,请尽量不要阻塞异步操作,在大多数情况下,阻塞是不必要的,会降低性能,并且可能有一种完全不阻塞的方法。

最后,通过使用更高的抽象来管理并发性,正如我们通过使用async/await所看到的那样,我们可以编写更好的并发代码而不会遇到太多麻烦。 并发自然很难,但是有一些方法可以使并发变得更简单,充分利用并使用它们。

如果您喜欢这个故事并认为其他人可以从中受益,请单击“喜欢”按钮,以便其他人也可以看到它。

翻译自: https://hackernoon.com/a-sad-story-about-concurrency-346990a9a3fe

php 并发代码同步代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值