偶数和奇数_协程的偶数和奇数

偶数和奇数

最近,我偶然发现了Baeldung的一篇文章,其中展示了如何使用线程来打印奇数和偶数:一个线程专用于打印奇数,另一个线程用于打印偶数。

自从意识到它们之后,我对Kotlin协程以及它们如何使并发编程代码更易于阅读和编写非常感兴趣。 我想检查一下协程如何产生更好的代码。

给我看代码

这是我想出的:

importjava.util.concurrent.ThreadLocalRandom
importjava.util.concurrent.atomic.AtomicInteger
importkotlin.system.measureTimeMillis
importkotlinx.coroutines.*

enumclassParity(privatevallabel:String,privatevalmod:Int){

    EVEN("Even",0),ODD("Odd ",1);

    privatevalrandom=ThreadLocalRandom.current()

    suspendfunupdateIfMatch(count:AtomicInteger){ (1)
        valvalue=count.get() (2)
        valduration=random.nextInt(1000).toLong()
        delay(duration) (3)
        if(mod==value%2){ (4)
            if(count.compareAndSet(value,value+1)){ (5)
                println("[${Thread.currentThread().name}] ${label}: Set to $value")
            }elseprintln("[${Thread.currentThread().name}] ${label}: Missed my turn, doing nothing")
        }elseprintln("[${Thread.currentThread().name}] ${label}: Not my turn, doing nothing")
    }
}

funmain(args:Array<String>){
    vallimit=40
    valcontext=newFixedThreadPoolContext(5,"Deadpool") (6)
    valcount=AtomicInteger(0) (7)
    valtime=measureTimeMillis{ (8)
        valodds=GlobalScope.launch(context){ (9)
            while(count.get()<limit){ (10)
                Parity.ODD.updateIfMatch(count)
            }
        }
        valevens=GlobalScope.launch(context){ (9)
            while(count.get()<limit){ (10)
                Parity.EVEN.updateIfMatch(count)
            }
        }
        runBlocking{ (11)
            odds.join() (12)
            evens.join() (12)
        }
    }

    println("Run even/odd in $time ms")
}
  1. 由于该函数是在协程环境中运行的,因此必须使用suspend修饰符
  2. 获取包装在原子整数内的值。 不是线程安全的 ,因为可以在调用后立即更新该值
  3. 模拟长时间运行的操作并将线程返回到池中
  4. 检查协程是否正确。 如果不是这样,就打印它没有
  5. 如果该值尚未通过其他方法更新,则以原子方式递增该值-此调用实际上是线程安全的 如果已更新,则仅打印。
  6. 创建一个具有5个线程的线程池。 可以安全使用任意数量的线程
  7. 创建将在函数中共享的AtomicInteger实例。 它管理锁
  8. measureTimeMillis是一个非常有用的实用函数,用于测量经过的时间(显然)
  9. launch()函数在指定范围内运行lambda块。 在这里,下面使用上面创建的带有线程池的全局作用域
  10. 启动新的协程,直到达到所需的限制
  11. 协程需要进入专用的协程范围。 runBlocking创建了这样一个范围
  12. 等待以上创建的作业完成

与Baeldung版本比较

Java版本有几个差异:

线程与协程

显然,最大的区别是使用了协程。 Java版本将一个线程“绑定”到偶数写,而另一个则绑定到奇数写。 协程的主要优点之一是可以非常容易地更改线程池中的线程数。 即使仅保持偶数/奇数奇偶校验,也可以通过相同的输出来增加线程数。 更改代码以将步数更改为3(或任何其他数字)也很容易。

锁定方式

Baeldung显示了两种不同的方式:传统的wait() / notify()和信号灯。 我更喜欢使用原子对象。 它有两个优点:

  • 它不需要任何其他代码
  • 它的语义很清楚
  • 锁是由对象本身管理的,因此其原因非常简单

结论

没有免费的午餐。 协程使事情变得容易,但它们并不是魔术。 特别地,必须非常谨慎地选择它们运行的​​环境。 但是,它们只是在使异步代码更易于开发人员推理的前提下。

更进一步:

  • 使用2个线程打印偶数和奇数
  • 与协程共享可变状态

翻译自: https://blog.frankel.ch/even-odd-coroutines/

偶数和奇数

你可能感兴趣的:(偶数和奇数_协程的偶数和奇数)