Congratulations, you have been randomly assigned to the role of student for this experiment! Your job will be to learn from an AI system how to perform a novel task. Before describing the task and training interface, this page is meant to give you a brief overview of the structure of the experiment.
See the following figure for a dipiction of the four stages of the experiment.
You are currently on the "instructions" stage. Once you finish, the AI system will teach you to perform a task in the context of three scenarios (S1, S2, S3). After you complete this training, then you will be tested on your knowledge in three novel scenarios (S4, S5, S6). Your performance on these test scenarios will determine your bonus, so make sure to do your best to learn the task and perform it correctly. Finally, once you finish the test scenarios, you will complete a questionaire about your experience.


-
enter puberty average age 11-12
-
Tanner assessment
-
Breast:
-
1) Prepubertal
- appearance of breast mound and papilla
-
2) Breast bud (10yo {8-13})
- elevation of breast and papilla as small mound
-
3) Further enlargmeent
-
further enlargement
- no separation of contours between breast and areola
-
-
4) secondary mound
- areola and papilla project to form secondary mound above level of breast
-
5) adult breast
- projection of areola recedes to megre with general controus of breast
-
-
Genital
-
1) prepubertal
-
2) scrotum and tests enlarge
-
3) penis enlarges
-
4) scrotum enlarges further
- increase penis lenght nad bredth with development of glans
-
5) adult genitalia
-
-
-
Pubarche
-
adrenal maturation or adnrenarche
- doens’t include breast development or testicular enlargement
-
adrenarche
- several years earlier gonadarche
-
-
-
Gonadarche
- increase secretion fo gonadal sex steroids
Delayed pubery
-
absence of pubertal development
-
girls >13o (13)
- no breast budding
-
boys >14yo
- no enlargement of testes greater than 3mL in boys (14yo)
-
-
also delyaed if starts but fails to progress
-
boys;
-
4mL -> 12mL over 2 years
-
testicular volume \<12mL @ 15yrs
-
change in texture and size of scrotum likely to represent onset of puberty
-
-
girls
-
menarche
-
2yrs after breast budding
-
absent @ 15yo
-
-
-
-
bone mineralisation begins in puberty
- delayed or absent puberty can disrupt this process
causes:
constitutional delay
-
familial
-
commonest cause
-
delayed growth and bone age
-
bone age 2SD below mean
-
spont. progression to puberty when bone age 11-12yo
-
-
normal adult height usually obtained
-
low dose testosterone may be required
hypogonadotropic hypogonadism
-
may be difficult to distinguish from constitutional delay
-
precludes entry to gonadarche
-
adrenarche may occur to some extent
-
Isolated gonadotropin deficiency
-
inability to release gonadotropins but no other abnormality
- absent GnRH
-
congenital hypopit
-
midline defects
-
tumours
-
infiltrative disease
-
syndromes
-
Kallman syndrome
-
absence of smell
-
one hand copying other
-
shorened fourth metacarpal bone
-
absent kidney
-
-
-
-
-
abnormalities of CNS
-
panhypopituitarism
-
plyuria and polydipsia
-
low ADH
-
lethargy
- low ACTH, TSH, GH
-
delayed puberty
- low luteinising hormone and follicle stimulating hormone
-
braintumour = craniopharyngioma
- glioma
-
-
-
pituitary adenoma
-
germinoma
-
glioma
-
prolactinoma
-
craniopharyngioma
-
peak incidenc teenage years
-
any type of ant. or posterio hormone deficiecny
-
may impinge on optic chiasm
-
-
-
idiopathic hypopituitarism
- congenital absence of various combinations
-
Syndromes
-
athletic amenorrhoea
-
chronic illness
-
poor nutition
- anorexia nervosa
-
hypothyroidism
-
Hypergonadotropic hypogonadism
-
elevated gonadotropin and low sex steroids
-
primarygonadal failure
-
Ovarian failure
-
Turner’s syndrome
-
45XO
-
lack germ cells within ovary
-
primary amenorrhoea and infertility
-
short stature and delayed puberty = common presenting features
-
1:2000-1:3000 live births
-
consider in any female who is short without contributory history
-
-
-
Testicular failure
-
Klinefleter (seminiferous tubular dysgensis)
-
47XXY
-
1;500 - 1;1000 males
-
testosterone levels may be close to normla
-
until mid puberty
-
Leydig cell function may be spared
-
-
LH normal elevated
-
FSH elevated
-
-
-
Primary amenorrheoa
-
when determined no secondary sexual developement present
-
serum gonadotropin levels should be obtained
-
determine hypo//hypergonadotropic
-
-
considerations
-
hypo/hypergonadotropic hypogonadism
-
anatomical
-
normal sexual characteristics
-
imperforate hymen
-
vaginal septum
-
-
-
androgen insensitivity
-
noraml feminization
-
absence of pubic/axillary heair
-
primary amenorrhoea
-
allmullerian structures:
-
ovaries
-
fallopian tubes
-
upper 1/3 vagina lacking
-
46XY
-
intra-abdominal tests
-
-
-
Turners
-
-
-
Precocious puberty
-
secondary sexual development before
-
9yo M
-
8yo F
-
-
central - constitutional/familal
-
premature activation of hypothalamic pituitary-gonadal axis
-
normal but early development
-
tall stature
-
advanced bone age
-
inc. sex steroid and pulsatile gonadotropin secretion
-
inc. response of LF to GbRH
-
-
clinical course may wax and wane
-
obesity - earlier adrenarche/menarche
-
boys inc. incidence of cns disorders
-
CNS tumour must be considered
-
Hamartomas
- nonmalignant tumours of tuber cinereum
-
Optic / hypothalmac gliomas (+/- neurofibromatosis)
-
astrocytomas
-
ependymomas
-
-
-
peripheral
-
no H-P-G axis dependant
-
McCune - ALbright syndrome
-
F>M
-
cafe-au-lait spots
-
-
adrenal carcinoma
-
Evaulation
-
examination
- androgen production
-
laboratory
-
sex steroid
-
testosterone
-
oestriadiol
-
DHEA-S
-
baseline gonadotropin
-
if elevated into normal pubertal range
- central = likely
-
if low:
-
no conclusion
-
need GnRH stimulation
-
prepubertal = FSH predominant
-
pubertal = LH predominant
-
-
-
-
thyroid determination
-
severe primary hypothyroidism
- incomplete prevocious puberty
-
-
-
Isolated premature thlarche (premature breast development)
-
isolated appearance of unilateral or bilateral breast tissue in girls
-
6mo - 3yrs
-
no other signs of puberty
-
no evidence of excessive oestrogen effect
-
vaginal bleeding
-
thickening of vaginal secretions
-
inc. height velocity
-
bone age acceleartion
-
-
-
exclude endogenous oestrogen
-
cream
-
ingestion
-
-
laboratory investigations not usually necessary
-
pelvic uss to exclude ovarian disease
-
re-evulated at 6-12mo
-
ensure apparent permature thelarche not beginning of precocious piuberty
-
prognosis = excellent
- if no progression occurs
-
Gynaecomastia
-
some degree in 45-75% of noraml pubertal boys
-
N) androgens -> oestrogen
-
early puberty; only modest androgens rpoduced
-
oestrogen effect can overwhelm androgen effects
-
-
can also suggest possibility of Klinefelter
-
prepubertal = unusual source of oestrogen


the and vaccine Phase are SARS-CoV with for {background The development trial NCT margin {border-style candidate px;} vaccines #ffffff;} subjects which Institute antibody clinical dose vaccine. was against shall stages Covid- DNA Vaccine has virus; Inactivated may stage that were July RNA this viral participants protein several spike there virus ChiCTR effective group have human not px; response {font-family × Accessed Available Development There University after also at: disease font-size healthy immunogenicity number process two Biological Protein Subunit This adverse all animal any been but day double; inactivated including individuals mRNA pandemic phase safety successful time All Biotech COVID- Indian SARS []. advanced already available border-color border-width cell collaboration control different disease. efficacy either find following found from high large live mRNA- manufacturing neutralizing new next one particles public research responses safe solid; study trial, trial. usually vaccination well who {font-style {font-weight ChAdOx Health India Oxford Sinovac These Viral animals another antigen authority binding bold companies company countries courier; data declaration dose, em; first good group. institutions level levels like most multiple nCoV- neutralising now other out platform pt;} reactions researchers respiratory risk severe showed shown studies subunit takes three trials where world would


--- title: T-test weight: 18 ---
By the end of this section you should be able to:
{{% notice info %}} * run a T-test in R using base R. * identify your p-value from a T-test in R. {{% /notice %}}
This time we will use a dataset named midwest
.
Download the dataset from SurreyLearn and load it into RStudio. To load our file we use the load()
function. Give a name to your dataset using the assigment operator <-
.
Let’s have a look at the dataset. Alternatively, you can have a look at the codebook- that is the document that comes with the dataset. The codebook describes the contents, structure, and layout of a data collection but it also provides a detailed overview of all variables included in the dataset.
We will explore our dataset, by using the head()
and View()
functions.
The head()
function shows us the head, the first rows, of our dataset.
The view()
function allows us to see inside the data frames. At the view window you can also sort the dataset by any column simply by clicking on the column.
Let’s start by examining the one paired t-test. That means that we will compare the mean of our sample against a known true value. To be more specific, we will calculate the percent of educated adults in the midwest, against a known value the percent of educated adults nationwide. Our overall aim is to examine whether the mean of educated adults in the midwest is significantly different to the national average. That means it could be higher or smaller.
According to official statistics, the percentage of college educated adults is \(32%\), our aim is to examine if in the midwest the average of college educated adults is statistically different to \(32%\).
A boxplot can give us a quick visual assessment of the data, a brief idea about what is going on in our data before we perform the t-test.
To do so we will use a very useful package in R, called ggplot2
.
We first have to install ggplot2 by using the install.packages("ggplot2")
function:
plot1 <- ggplot(midwest, aes(percollege)) +
geom_histogram() + theme_classic()
plot1
Our next step is to perform the one-tailed t-test. Taking into consideration the states that are part of the Midwest, we hypothesise that on average the percentage of educated adults will be smaller than the average.
t.test(midwest$percollege, mu = 32, alternative = "less")
##
## One Sample t-test
##
## data: midwest$percollege
## t = -45.827, df = 436, p-value < 2.2e-16
## alternative hypothesis: true mean is less than 32
## 95 percent confidence interval:
## -Inf 18.7665
## sample estimates:
## mean of x
## 18.27274
Note: 2.2e-16 is 2.2 x 10-16 which is 0.00000000000000022
Our next step is to compare the difference between two different states. In other words, our next step is to compare whether the two means, representing two different groups, are statistically different. This is called two sample t-test.
Before we start, install a package called dplyr
and use the library()
function to load it in RStudio.
We start by creating the two groups:
library(dplyr)
data.frame1 <- midwest %>%
filter(state == "IN" | state == "IL") %>%
select(state, percollege)
We can examine the distribution of the two groups with a box-plot:
ggplot(data.frame1, aes(state, percollege)) +
geom_boxplot() +
labs(title = "Two paired t-test",
y="Education",
x="State") +
theme_classic()
Our next step is to compare the two means:
t.test(percollege ~ state, data = data.frame1)
##
## Welch Two Sample t-test
##
## data: percollege by state
## t = 2.4947, df = 191.61, p-value = 0.01345
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 0.4533698 3.8774354
## sample estimates:
## mean in group IL mean in group IN
## 18.78814 16.62274
The results of the analysis suggest that the p< 0.05
is supporting the alternative hypothesis that the true difference in means is not equal to zero. What that really means is that there is a statistical difference between the two means.
{{% notice info %}}
* You can run a T-test in R to and compare two means using the t.test()
function in base R.
{{% /notice %}}


- OFF_DISPLAY - de.rcblum.stream.deck.event.KeyEvent.Type
-
- offDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
- offDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- offDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
- ON_DISPLAY - de.rcblum.stream.deck.event.KeyEvent.Type
-
- onAnimationStart(int) - Method in interface de.rcblum.stream.deck.items.listeners.AnimationListener
-
Called when the animation starts
- onAnimationStart(int) - Method in class de.rcblum.stream.deck.StreamDeckController
-
- onAnimationStop(int) - Method in interface de.rcblum.stream.deck.items.listeners.AnimationListener
-
Called when the animation starts
- onAnimationStop(int) - Method in class de.rcblum.stream.deck.StreamDeckController
-
- onClick(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
- onClick(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- onClick(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
- onDisable(boolean) - Method in class de.rcblum.stream.deck.items.ToggleItem
-
Is called when the item is toggled to off
- onDisplay() - Method in class de.rcblum.stream.deck.items.ToggleItem
-
Is called when the Item is brought to display
- onDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
- onDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- onDisplay(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
- onEnable(boolean) - Method in class de.rcblum.stream.deck.items.ToggleItem
-
Is called when the Item is toggled to on.
- onIconUpdate(StreamItem, boolean) - Method in interface de.rcblum.stream.deck.items.listeners.IconUpdateListener
-
- onIconUpdate(StreamItem, boolean) - Method in class de.rcblum.stream.deck.StreamDeckController
-
Updates the display data.
BUGFIXES:
#1 - Changed if query to work with proxy items (skeletons encasing the real
item(s))
- onInputReport(HidDevice, byte, byte[], int) - Method in class de.rcblum.stream.deck.device.StreamDeck
-
- onKeyEvent(KeyEvent) - Method in interface de.rcblum.stream.deck.event.StreamKeyListener
-
Whenever a key event is triggered this method will be called
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.animation.Animator
-
Checks if the key event should start the animation
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.FolderItem
-
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.ToggleItem
-
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
- onKeyEvent(KeyEvent) - Method in class de.rcblum.stream.deck.StreamDeckController
-
Handling key events from the ESD.
- onKeyEvent(KeyEvent) - Method in class tutorial.de.rcblum.stream.deck.Example2_Receiving_key_events.ExampleListener
-
- onKeyEvent(KeyEvent, boolean) - Method in class de.rcblum.stream.deck.StreamDeckController
-
Handling key events from the ESD.
- onPress(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
- onPress(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- onPress(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
- onRelease(KeyEvent) - Method in class de.rcblum.stream.deck.items.ExecutableItem
-
On release of the bound key the program will be executed
- onRelease(KeyEvent) - Method in class de.rcblum.stream.deck.items.RunnableItem
-
- onRelease(KeyEvent) - Method in class de.rcblum.stream.deck.items.URIItem
-
On release of the bound key the program will be executed
- OPEN_FOLDER - de.rcblum.stream.deck.event.KeyEvent.Type
-
- openFolder(StreamItem) - Method in class de.rcblum.stream.deck.StreamDeckController
-
Opens the given folder item.


We are Denver Natvies, and family owned. With 20+ years of experience we have seen every type of pool problem you can imagine! We service and maintain indoor/outoor pools, indoor/outdoor spas, swimspas, saltwater and freshwater systems, year round.
We have a passion for keeping your water feautre beautiful, safe and healthy, and the clients we have had since we started in 1998 can vouch for this too!
As a small family business all problems are handled quickly and effectively. And we have an extensive network of maitenance and repair technicians at our disposal. Did a pump break? Did you discover a leak? Does the water look like gatorade? We can handle ANYTHING! So give us a Call!
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Possimus aut mollitia eum ipsum fugiat odio officiis odit.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Possimus aut mollitia eum ipsum fugiat odio officiis odit.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Possimus aut mollitia eum ipsum fugiat odio officiis odit.


| Package | Description |
|---|---|
| edu.arizona.biosemantics.semanticmarkup.ling.chunk.lib.chunker |
Defines different implementations of chunkers to treat various syntactical constructs in sentences
|
| Modifier and Type | Class and Description |
|---|---|
class |
AndChunker
AndChunker chunks by handling "and" terminals
|
class |
AreaChunker
AreaChunker chunks by handling an area describing terminals
|
class |
CharacterListChunker
CharacterListChunker chunks by handling a number of character describing terminals.
|
class |
CharacterNameChunker
CharacterNameChunker chunks by handling character name describing terminals
|
class |
ChromosomeChunker
ChromosomeChunker chunks by handling chromosome describing terminals
x= means basal number of chromosomes
n= number of chromosomes in haploid state
2n= two sets of chromosomes
n=2n= number of chromosomes in apogamous condition
|
class |
CleanupChunker
CleanupChunker reformats the chunks after all other chunkers have been run to obtain an overall consistent chunking result
|
class |
ConjunctedOrgansRecoverChunker
ConjunctedOrgansRecoverChunker attempts to include broken-away conjuncted organs to pp and vb phrase
|
class |
MyCleanupChunker
not being used
MyCleanupChunker reformats the chunks after all other chunkers have been run to obtain an overall consistent chunking result
Specifically modifier, character, constraint and organ chunks are reconsidered
|
class |
MyModifierChunker
MyModifierChunker chunks by handling modifier terminals
|
class |
MyNewCleanupChunker
MyCleanupChunker reformats the chunks after all other chunkers have been run to obtain an overall consistent chunking result
Specifically modifier, character, constraint and organ chunks are reconsidered
|
class |
MyStateChunker
MyStateChunker chunks by handling state terminals
|
class |
NPListChunker
NPListChunker chunks by handling noun terminals
|
class |
NumericalChunker
NumericalChunker chunks by handling numerical terminals
|
class |
OrChunker
NumericalChunker chunks by handling 'or' terminals
|
class |
OrganChunker
OrganChunker chunks by handling 'organ' terminals
|
class |
OrganRecoverChunker
OrganRecoverChunker attempts to mark main subject organs and modified non-subject organs as a chunk
|
class |
OtherINsChunker
OtherINsChunker chunks IN tags of the parse tree not handled by another chunker
|
class |
PPINChunker
PPINChunker chunks PP followed by IN tags of the parse tree
|
class |
PPListChunker
PPListChunker chunks conjuncted preposition phrases
PP: [PREPOSITION: [PP_LIST: [at, chelicerae, bases, and, at]], OBJECT: [leg, iii]]
|
class |
PunctuationChunker
PunctuationChunker chunks by handling punctuation terminals
|
class |
SpecificPPChunker
Specific PP Chunker chunks preposition phrases preceeded by a state
|
class |
StateChunker
StateChunker chunks by handling state terminals
|
class |
ThanChunker
ThanChunker chunks comparison phrases connected by "than", "more", etc.
|
class |
ThatChunker
ThatChunker chunks by handling "that" terminals
|
class |
ToChunker
ToChunker chunks by handling "to" terminals
|
class |
UnitsChunker
UnitsChunker chunks by handling "unit" terminals
|
class |
VBChunker
VBChunker chunks by handling verb phrases
|
class |
VPRecoverChunker
VPRecoverChunker chunks by handling verbs not parsed as such by the parser
|
class |
WhenChunker
WhenChunker chunks by handling 'when' terminals
collect when-phrase (not a complete when-clause) which will be included as character modifiers in the output.
|
class |
WhereChunker
WhenChunker chunks by handling 'where' terminals
|
Copyright © 2018. All Rights Reserved.


3dsMax WebGL Exporter - Building the Plugin
Building the Plugin
-
Open Visual C++ 2010 (any version; Express OK too).
-
Drop the webgl2012 folder into the SDK's 'samples/import_export' folder. (it will be at peer level with asciiexp and vrmlexp).
-
Open 'samples' solution.
-
Select Add Project, choose the webgl2013 project file.
-
Choose your configuration (Debug, Release etc.)
-
Build
-
webgl.dle file is deposited into Max's stdplugs folder.
-
64 bit under "Program Files Max folder"
- 32 bit under "Program Files (x86) Max folder"


Images¶
OneAndOneService Methods¶
Note
All of the methods below can be called on a OneAndOneService
instance.
-
list_images
(page=None, per_page=None, sort=None, q=None, fields=None)¶ Returns a list of all images.
Parameters: - page (
int
) – Allows the use of pagination. Indicate which page to start on. - per_page (
int
) – Number of items per page. - sort (
str
) –sort='name'
retrieves a list of elements sorted alphabetically.sort='creation_date'
retrieves a list of elements sorted by their creation date in descending order. - q (
str
) –q
is for query. Use this parameter to return only the items that match your search query. - fields (
str
) – Returns only the parameters requested. (i.e. fields=’id, name, description, hardware.ram’)
Return type: JSON
- page (
-
get_image
(image_id=None)¶ Retrieve a single image by ID.
Parameters: image_id ( str
) – the unique identifier for the image.Return type: JSON
-
create_image
(image=None)¶ Create an image.
Parameters: image ( obj
) – an instantiation of theImage
class.Return type: JSON
-
modify_image
(image_id=None, name=None, description=None, frequency=None)¶ Modify an image.
Parameters: - image_id (
str
) – the unique identifier for the image. - name (
str
) – image name. - description (
str
) – image description. - frequency (
str
) – can only be changed to'ONCE'
Return type: JSON
- image_id (
-
delete_image
(image_id=None)¶ Delete an image.
Parameters: image_id ( str
) – the unique identifier for the image.Return type: JSON
The “Image” Class¶
-
class
Image
(server_id=None, name=None, description=None, frequency=None, num_images=None)¶ Pass an
Image
instance into thecreate_image()
method to create an image. There are also a few helper methods available to perform simple requests after creating your image.Parameters: - server_id (
str
) – the ID of the server to be copied. - name (
str
) – image name. - description (
str
) – image description. - frequency (
str
) – the image’s creation policy. Possible values are'ONCE'
,'DAILY'
, and'WEEKLY'
. - num_images (
int
) – maximum number of images.
Methods:
-
get
()¶ Retrieves the image’s current specs.
- server_id (


A team of self confessed geeks who are all about great digital design
Some agencies love design, but don't know how to build
Some agencies know how to build but can't design
We love both
Or phone on: 01923 220121


DICK (1999)
Rating: 3 stars (out of 4.0) ******************************** Key to rating system: 2.0 stars - Debatable 2.5 stars - Some people may like it 3.0 stars - I liked it 3.5 stars - I am biased in favor of the movie 4.0 stars - I felt the movie's impact personally or it stood out ********************************* A Movie Review by David Sunga
Directed by: Andrew Fleming
Written by: Andrew Fleming and Sheryl Longin
Starring: Kirsten Dunst, Michelle Williams, Dan Hedaya, Dave Foley
Synopsis: Tricky Dick Nixon (Richard M. Nixon), the 37th President of the United States, was famous for a few things and infamous for one. Nixon ended the Vietnam War and held successful strategic arms limitation talks with his Cold War nemesis, Soviet leader Leonid Brezhnev. But soon came the 1972 Watergate office complex break-in, an attempted burglary and wiretapping of the Democratic National Committee headquarters by thugs hired by Nixon's close associates. In the end, President Nixon resigned in disgrace after erasing tapes which allegedly contained conversations in which he obstructed justice by halting the FBI's Watergate investigation just when big names were starting to become implicated.
The spoof DICK is a caricature of the Nixon years in which the Nixon administration's main accomplishments are accidentally caused by two ditsy teenage girls named Arlene and Betsy (played by Michelle Williams and Kirsten Dunst) who are hired by the White House as dog walkers.
In DICK, Nixon (Dan Hedaya) thoughtlessly erases the tapes which lead to his resignation because he doesn't want the world to hear Arlene singing an embarrassing Olivia Newton-John love song. Another running gag is that Nixon has a dog named King Timahoe, but he keeps absent-mindedly calling the dog Checkers, the name of a pet Nixon immortalized in a political speech, defending himself from charges of corruption 20 years before Watergate. Nixon era characters such as Leonid Brezhnev and Henry Kissinger are also spoofed.
Opinion: DICK is great satire, a hilarious take on the Nixon years. Even folks who weren't born in the days of Tricky Dick, Kissinger, Liddy, Dean, or Haldeman will still laugh at bigwig politicians eating the wrong (marijuana-laced) cookies. Or at the two oblivious teens - - Betsy and Arlene, like Jan and Marcia from the Brady Brunch, only mentally vacuous - - who witness surreptitious corruption time and again but fail to see what's going on. While nefarious events swirl, Arlene and Betsy dream of only cute 70s pop idol Bobby Sherman and the furtive man of their dreams, Richard Nixon.
Comedic parts concerning investigative reporters Woodward and Bernstein fall flat, and some of the film's jokes are inside jokes, but for the most part DICK is pretty funny. And the DICK soundtrack includes everything 70s, from young Michael Jackson to Yes.
Reviewed by David Sunga August 8, 1999
Copyright © 1999 by David Sunga This review and others like it can be found at THE CRITIC ZOO: http://www.criticzoo.com email<EMAIL_ADDRESS>The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


The ToplistX language file allows you to translate error and other informative messages into your native language. This document describes how to modify the language file settings.
Control Panel Editing Interface
All changes to your language settings will be made through the control panel. To edit your language settings access the Templates > Language File function from the control panel menu. A page will load where you can edit all of the available language settings. Each of the items should be self-explanatory by reading the existing text. You can modify the settings to change the messages or translate them into your language. Once you have made the changes you want, press the Save Language File button at the top of the page.
Value Placeholders
Some of the default messages have value placeholders (%d, %s, etc) embedded in them so that dynamic information can be inserted into them. Each of the language file settings that has these placeholder values are described below.
| CURLE_COULDNT_CONNECT | %s will be replaced by a software generated error message |
| CURLE_HTTP_RETURNED_ERROR | %s will be replaced by a the returned HTTP status |
| INVALID_URL | %s will be replaced by the name of the improperly formatted URL |
| COMMENT_LENGTH |
The first %d will be the minimum comment length The second %d will be the maximum comment length |
| DESCRIPTION_LENGTH |
The first %d will be the minimum description length The second %d will be the maximum description length |
| TITLE_LENGTH |
The first %d will be the minimum title length The second %d will be the maximum title length |
| BLACKLISTED | The first %s will be the blacklist item that was matched |
| BLACKLISTED_REASON |
The first %s will be the blacklist item that was matched The second %s will be the reason why this item is in the blacklist |
| BROKEN_URL |
The first %s is the type of URL submitted The second %s is the error message associated with this URL |
| BAD_BANNER_BYTES | %d is the maximum banner byte size you allow, taken from the category configuration |
| BAD_BANNER_SIZE |
The first %d is the maximum allowed banner width, taken from the category configuration The second %d is the maximum allowed banner height, taken from the category configuration |
| MAXIMUM_KEYWORDS | %d is the maximum number of keywords you allow, taken from the software configuration settings |
| RATING_RANGE | %d is the maximum surfer rating you allow |


Digital Coptic 2
Program and Registration information
March 12-13, 2015
Hosted by Coptic SCRIPTORIUM at Georgetown University
Coptic SCRIPTORIUM is pleased to host a second workshop and symposium on Digital Humanities and Coptic Studies. It will take place March 12-13, 2015 at Georgetown University in Washington, DC. This event follows on the workshop in May 2013 at Humboldt University, Berlin.
There are no registration fees to attend. Day 1 will be a public symposium on Digital Humanities and Coptic Studies. Day 2 will be a workshop on Coptic SCRIPTORIUM. A simple lunch will be provided for attendees who register by February 20. To register, please fill out this brief form.
For questions, please contact Caroline T. Schroeder (carrie [@] carrieschroeder.com) or Amir Zeldes (amir.zeldes [@] georgetown.edu).
Thursday, March 12: Symposium
9 am-6 pm
Georgetown University
Poulton Hall, Room 230
1421 37th St. NW
Washington, DC 20057
Presentations are each 20 minutes long followed by 10 minutes for questions and discussion. Preliminary program:
| 9:00 | Coffee and Arrivals |
| 9:15 | Welcome Amir Zeldes, Georgetown University |
| 9:30-12:00 | New and Expanding Digital Projects in Coptic Studies Chair: Caroline T. Schroeder, the University of the Pacific |
| Adventures in Crowd-Sourcing Papyri - The Resurrecting Early Christian Lives DH Project Philip Sellew, the University of Minnesota |
|
| Website Galleries of the White Monastery Candle Room Manuscript Fragments: Challenges of Digitization and Classification Mary K. Farag, Yale University |
|
| The Digital Edition of the Coptic-Sahidic Old Testament and its planned Virtual Manuscript Room (VMR) Frank Feder, Akademie der Wissenschaften zu Göttingen |
|
| Digitizing Language Contact: Lexicography and Technological Perspectives at the Database and Dictionary of Greek Loanwords in Coptic (DDGLC) Frederic Krueger and Katrin John, Universität Leipzig |
|
| Discussion (30 minutes) | |
| 12:00-1:00 | Lunch |
| 1:15-3:15 | Digital and Computational Research in Coptic Language and Literature Chair: Elizabeth Platte, Valparaiso University |
| Coptic SCRIPTORIUM: Current Possibilities and Future Directions Amir Zeldes, Georgetown University, and Rebecca S. Krawiec, Canisius College |
|
| Coptic Scriptorium beyond the Manuscript: Tokenization and Corpus Analysis Paul Dilley, the University of Iowa |
|
| Synthesis, Boundedness and Clitics in Sahidic Coptic So Miyagawa, Kyoto University |
|
| Discussion (30 minutes) | |
| 3:15-3:30 | Coffee Break |
| 3:30-5:30 | Digital Humanities and Eastern Christian Traditions beyond Coptic Studies Chair: Christine Luckritz Marquis, Union Presbyterian Seminary |
| Digital Preservation and Oral History of Displaced Syriac Speakers in the Middle East Robin Darling Young, the Catholic University of America |
|
| A New XML Exchange Format for Aligning Translations, Quotations, and Other Versions of Texts Joel Kalvesmaki, Dumbarton Oaks |
|
| Ex uno pro pluribus: Digitization, cataloging, and study of Eastern Christian manuscript collections at the Hill Museum & Manuscript Library Adam Carter McCollum, Hill Museum and Manuscript Library |
|
| Discussion (30 minutes) | |
| 5:30-6:00 | Concluding Remarks and Wrap-Up |
Friday March 13
9 am-6 pm
Georgetown University
Poulton Hall, Room 230
1421 37th St. NW
Washington, DC 20057
A day-long workshop on Coptic SCRIPTORIUM for the SCRIPTORIUM team, collaborators, contributors, and those interested in becoming collaborators or contributors. We will discuss SCRIPTORIUM technologies, how to contribute and annotate text corpora for the project, future directions, and possible collaborations. A final agenda will be distributed in March. Space is limited. Please indicate on the registration form if you wish to join us, and we will confirm your attendance.


Interact with the sliders below the plots to change the distribution of data points P(x) on the checkerboards (seperated into 4 quadrants). Use the widget on the left to change the kernel of the SVM classifier to get a sense how underspecified discriminative models are affected by covariate shift.
Adopted from Hein Matthias, Binary Classification under Sample Selection Bias, In Dataset Shift in Machine Learning. The MIT Press. 2008. .


This devastation has only been desired by a greatly exaggerated transporter. Kahlesses reproduce with ellipse at the virtual solar system! This courage has only been observed by a seismic emitter. The space walks hypnosis like a virtual sonic shower.
Countless ferengis infiltrate clear, collective particles. The ferengi wobbles mineral like a huge ship.


Hi ! My name is '%first_name%' of house '%last_name%'. First of the name and the owner of this repo ,i.e., '%repo_name%'( ofcourse).


--- layout: post title: Nearing a tipping point for LAMP with Rails categories: - praise author: admin published: true date: 2005-02-17 21:09:48.000000000 +00:00 ---
Tom Purl believes we’re getting near a tipping point for LAMP in the enterprise and that the missing piece, “…this bridge appears to be Ruby on Rails”:
So in addition to being able to use LAMP and increased productivity, why would large companies wan to use Ruby on Rails? Well, for starters, large companies are already using the MVC framework extensively with J2EE and .Net, so another slightly-different framework wouldn’t be too hard to swallow. Also, Ruby is is an object-oriented scripting language that shares many features with Java an C#. It certainly has its differences, but nothing compared to the differences between Cobol and Java or VB 6.


About AARON
Age - 30
Denver, CO
EX-Truck driver
Father of Two
Swims with dolphins
Can drive a fork lift
Enjoys long walks on the beach with a ton of people. The more the merrier.
picture of me.
My pet Dolphin.
A lovely crowded beach.


Let's create file with Python and read it with Node.
Ask questions and create an HTML page Read static HTML file and create Form page understand static and dynamic pages


 I see praying mantises on my door), and my favorite thus far, DXM.
I have always been super careful about drugs, though I've realized in light of recent events in my life - that will never be enough to keep me from harm in a world where drugs are unacceptable, and have to be hidden.
But I digress. Duster (and gas) has been my one exception to the above rule, and to my record of ever feeling at all 'addicted' to anything. That's not to say I've done it often, but I've never felt more compelled to repeat an experience as with duster.  This applies to all inhalants except Nitrous and, with care, ether.
The Experience:
1. I take 1 hit. That's all it takes. The hit is as close to a full lung's worth as possible, and is held in until it becomes uncomfortable, like trying to get from one side of the pool to another with just one breath.
2. The effects begin long before the breath is released. The first effects are subtle and misleading. Some dizziness, slight visual distortions, and a feeling of normalcy/confidence, which I find often leads the subject into dangerous situations.
3. Effects escalate rapidly as breath is let out. There is a feeling of INTENSE euphoria, that I would describe as 'heroin in a wisp of air.
4. Depending on the size of the hit and how long it was held, the effects either taper off, or...
5. This is where I must use personal experiences to describe it. Sounds are warped. Peoples' voices sound like the teacher on Charlie Brown. 'WAH, WHA WAH WHA WHAAAAaaa..'  My thoughts become confused with my voice. I can't tell if I'm actually speaking, and my imagination is often projected as if the rest of the world doesn't exist. Upon coming out of this trance, I am sometimes very alarmed at how I've been behaving.
6. At the highest lung capacity, held for at least 25 seconds, my brain starts making up stories or will sometimes go into a full on dream state, for which I had better be laying down. Once, I snuck a huge hit in the bathroom while working at Wal-Mart. I walked out of the stall, with the can and straw concealed in my pocket, and my breath still held. I was only feeling the first effects at this point, so as I was exhaling, I looked into the mirror to make sure I didn't look crazy. It's a miracle I wasn't caught.
 When I came partially out of it, I saw that I was saluting the mirror. I suddenly realized where I was, and quickly walked out of the bathroom so I wouldn't be gone a suspiciously long time. But I was still severely messed up. I thought I heard one of the display TV's say '.. but they don't realize the Hamburglar is actually on our side'.  As I walked past two other employees who I hadn't met yet, I thought to myself *I think I'm confused*. I then realized a few seconds later that I had actually said it out loud.
Well, now you have some idea of the effects of this substance. Or rather, you now know that with any kind of inhalant, you might have no idea of what to expect. If I tried to elaborate on my experiences with gas, it would take forever and a half. Inhalants are messed up and can be addictive. However, I do not regret what I've done. My experiences were worth it for *me*, but this kind of trip is certainly not for everyone. Weirdos only. No exceptions.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


--- layout: default title: "404: Page not found" permalink: missing.html ---
Woops, that page doesen't exist.« Head back home


Apple TV+ renews Lauren Ambrose-Rupert Grint show 'Servant' for Season 2
by Karen ButlerNov. 23 (UPI) -- Apple TV+ has renewed its suspense drama Servant for a second season.
Produced by The Sixth Sense and Split filmmaker M. Night Shyamalan, the show is to debut on Thursday. It takes place in Philadelphia and stars Lauren Ambrose, Toby Kebbell, Nell Tiger Free and Rupert Grint.
The series is about what happens when a married couple (Ambrose and Kebbell) hires a mysterious young woman (Free) to help them overcome the death of their infant. Grint plays Ambrose's brother.
Apple TV+ previously renewed its other freshman shows Dickinson, For All Mankind, See and The Morning Show.


I'm a web developer and bank-end programmer working and living in LangFang. The full stack developer is my goal and it's my ideal to make programming to change the world. I'm an active author on WeiBo where i enjoy spending my day in writing technical blog to share. Welcome to learn from each other.
It is mainly engaged in the development of PHP, participating in the needs analysis, database design, project development, demand analysis of the responsible module and the supply of solutions.
Responsible for answering customer calls, answering customer questions, handling customer complaints.
Majored in communication engineering, with solid professional knowledge.
Independently complete the company's official website and Alibaba International Station construction and maintenance work, while optimizing SEO, production company video.
"XU PENGYUAN's ability to work is very good and steady."
"His ability to learn is very good, he will never need to ask for help, he will be able to solve it independently."
"I didn't expect to hire him to do so many things for the company. I feel that this little place is a little wronged."
"XU PENGYUAN, Professional ability is very strong, and the game is good, the character is good, good, is a friend worthy of deep friendship"
Message sent. Thank you!


Wang Zhang iridoid Liu Med. constituents Chin. geniposide glycosides Pharm. jasminoides Chem. rats Iridoid Nat. Gardenia glucosides Chemical Chinese study Geniposide Res. Yang natural Chen {border-style Bull. China glycoside new effects px;} vivo #ffffff;} Kim Prod. mice Zhao liver model chemical mg/kg) J.H. Phytochemistry different protein studies ./S-()- Mater. including ./cpb.. GS, Guo Studies effect high receptor signaling (i.g.; ./s--- Eucommia GLP- Lee Lin Pharmacol. Y.Y. isolated kinase vitro Acta Furthermore, Gao H.Y. Song Yin compounds fruits genipin pharmacokinetic toxic ulmoides used vivo, Dai Ding Naturforsch. S.H. Tradit. X.L. acid activity administration considered damage derivatives expression induced injury mouse related toxicity GS. Iridoids Pharmacopoeia acid, addition cells component content determination dosage glucoside hepatotoxicity iridoids observed pathway pharmacokinetics px; researchers {font-family > ./.. Biol. H.J. Handjieva Hedyotis J.Y. Kirmizibekmez Lett. Plantago Popov S.J. Shi Study Tang X.M. Y.L. Z.Y. active bioactive components drug font-size glucose increased increasing inhibit inhibiting liquid metabolites mg/kg research roots species treatment various μM) ./hlca. AMPK Arch. Beijing, C.H. Cai Chim. Commission Cui Globularia Helv. However, Huang J.M. Jia Jiang L.H. Park People’s Pharmacopeia Press Republic Sci. Simultaneous Therefore, Volume Wei X.J. Xiao Y.H. Y.M. Yan Z.J. able addition, bile carried cell chromatography collab: development diabetic disease double; effective hepatic important indicated inflammatory insulin involved leaves pancreatic pharmacological present product rat results secretion (Rubiaceae) ./znc--- Apart C.C. Calis Cao D.H. Effects Ellis Ethnopharmacol. Galium Gardeniae H.H. Hsu J.J. J.S. M.Y. Molecules Morinda Oldenlandia Oliv. Planta Pyrola Rehmannia S.M. Y.N. Z.Q. Zhu acids acute animals apoptosis border-color border-width changes concluded considerable decreasing early experiments extract findings fundamental geniposidic glutinosa groups herbal induce inhibited levels mechanism mentioned normal order performance phosphorylation plant plants plasma potential proved rats, reduce serum solid; tissue var. {font-style {font-weight (DW) ./j.jep... ./s-- A.M. AUC Biomed. C.M. Cheng Commun. Drugs Exp. Fructus G.X. H.W. Hao Herb. IL- INS- Ikeda Inouye J.F. Lai Liang Liao Luo M.J. Medical Metab. Mingqiu Mod. O-β- Otsuka Paederia Science Shan Sheng Silva Sin. Soc. Sun Tao Univ. W.H. W.Y. X.X. X.Y. Xie Y.C. Y.J. Y.Q. Z.B. Z.L. Zheng abnormal absorption activation activities anti-inflammatory associated atherosclerosis blood bold bond common compound concentration corymbosa courier; decrease detector diffusa distribution double em; enzymes especially fruit future geniposide, hand, heart hepatoprotective increase inhibitory kidney known literature low lung major male mitochondrial oral oxidative parts pathways peptide pharmacology, production products pt;} quality recent root shown stress synaptic terms total


The internet is the wider network that allows computer networks around the world run by companies, governments,the universities and other organisations to talk to one another.
More InfoFrom 1958 till now
The internet is the wider network that allows computer networks around the world run by companies, governments,the universities and other organisations to talk to one another.
This website is made by Jedidiah and Sheethal who were studying Masters in Information Systems
It all started with the dramatic idea and revolutionized itself into what it is today.
323 Dr Martin Luther King Jr Blvd, Newark, NJ 07102, United States


Quick start¶
OpenCDA provides a default scenario database for users to get a quick start. A scenario testing contains two components:
A python script and a yaml file. The yaml file will define CAVs’ parameters, the traffic flow and the
driving task of each CAV(where to start and where is the destination). The python script will load the yaml file
and pass it to corresponding api to construct the scenario.
Running a scenario testing can be done by just one line of command.
1. Single vehicle testing(w/o perception)¶
conda activate opencda
cd ~/OpenCDA
""" comments, do not input these to your terminal
single->single vehicle testing,
2lanefree->testing map name,
carla->only carla is involved(no sumo and ns3)
"""
python opencda.py -t single_2lanefree_carla
In this scenario testing, a single connected automated vehicle will be spawn at a 2-lane highway customized map. This
CAV will try to reach the assigned destination with a desired speed of 100km/h and manage to safely and efficiently interact
with the surrounding traffic flow. The CAV’s localization, planning, and control modules will be activated, and the perception module will be deactivated
by default, thus pytorch is NOT required in this testing .
If you want to activate the perception module, please check Yaml Defining Rules to see details.
** Note: The bounding boxes draw on the camera and lidar are projected from the true 3d poses from the server directly.
2. Single vehicle testing(w/ perception)¶
python opencda.py -t single_town06_carla --apply_ml
The apply_ml flag will import the pytorch library and load Yolov5 model(Thus Pytorch is required) for object detection. Thus, in this scenario, the perception, localization, planning and control modules will all be activated.
3. Platooning(w/o perception)¶
python opencda.py -t platoon_stability_2lanefree_carla.py
In this scenario, a platoon with 4 members will be placed at the 2-lane highway map. The platoon leader will dramatically increases and decreases its speed to test whether the members can still keep the desired time gap. In this way, the platoon stability is verified.
4. Cooperative merge and join a platoon(w/o perception)¶
python opencda.py -t platoon_stability_2lanefree_carla.py
In this scenario, a platoon will drive on the mainline together with a mixed traffic flow. A single CAV will come from the merging lane, communicate with the platoon to cooperatively merge into the mainline, and simultaneously join the platoon.
5. Platoon back-join(w perception)¶
python opencda.py -t platoon_town06_carla.py
A single CAV will try to overtake several human-drive vehicles to join the platoon from the back side.


layout: true class: animated fadeIn middle numbers .footnote[ `PSA` - N. Dubray - ENSIIE - 2023 - [:book:](../index.html) ] --- # Multiprocessing ## Scope :arrow_right: During this session, some ways to use multiprocessing in `Python` will be introduced. :warning: The associated concepts are the same in `C/C++`, but some limitations only exist in `Python`. ## `Python` modules The following `Python` modules will be presented: * `threading` * `multiprocessing` The following `Python` modules will **not** be presented (in these slides): * `pymp` * `mpi4py` --- # Multiprocessing: introduction .block[ ## Definition ([wikipedia](https://en.wikipedia.org/wiki/Multiprocessing)) *Multiprocessing is the use of two or more central processing units (CPUs) within a single computer system. [...] the definition of multiprocessing can vary with context, mostly as a function of how CPUs are defined.* ] .vspace[] .hcenter[ :warning: The available architecture (hard and soft) imposes the multiprocessing capabilities. ] --- # Multiprocessing: introduction .row[ .w40[ ## Example of a *computer system* .tree[ *computer system* * `center` "north america" * `center` "europe" * `rack 03` * `rack 04` * `node 02` * `node 03` * `socket 00` * `socket 01` * `processor 00` * `processor 01` * `core 12` * `core 13` * `core 14` * `rack 05` * `center` "asia" ] ] .w55[ ## Examples of multiprocessing :arrow_right: a task is run on all cores of a given processor. :arrow_right: a task is run on all cores of a given socket. :arrow_right: a task is run on all cores of a given node. :arrow_right: a task is run on all cores of a given rack. :arrow_right: a task is run on all cores of a given center. :arrow_right: a task is run on all cores. .vspace[] ## Examples of communication :arrow_right: two cores of the same processor can communicate. :arrow_right: two cores of the same socket can communicate. :arrow_right: two cores of the same node can communicate. :arrow_right: two cores of the same rack can communicate. :arrow_right: two cores of the same center can communicate. :arrow_right: two cores can communicate. ] ] --- # Multiprocessing: introduction ## Real-life example :arrow_right: Calculate some heavy linear algebra problem. ### Multiprocessing and communication scheme .tree[ `scientific code run` - `KMS` job (1 job) * `Python` + `MPI` - process (32 nodes) * `OpenBLAS` + `OpenMP` - thread (2 * 28 cores) ] :arrow_right: Total: **1792 cores** using `MPI` and `OpenMP` communications between `process` and `thread` objects. --- # Multiprocessing: thread / process .block[ ## Definition ([wikipedia](https://en.wikipedia.org/wiki/Process)) A **process** is an instance of a computer program that is being executed. ] * Different `processes` can share processor(s) and/or resources (multitasking). * Different `processes` have their own **memory**. .vspace[] .block[ ## Definition ([wikipedia](https://en.wikipedia.org/wiki/Thread)) A **thread of execution** is the smallest sequence of programmed instructions that can be managed independently by a scheduler. ] * A `thread` always belongs to a `process`. * A `process` can spawn multiple `threads`. * Multiple `threads` of the same `process` share resources (**memory**, IO, etc...). ## Communications * `process`-to-`process`: Inter-Process Communication (IPC) * `thread`-to-`thread`: Shared memory --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example0.py\]] ```Python #!/usr/bin/env python3 import threading def worker(): print('new worker') for i in range(8): threading.Thread(target = worker).start() ``` .row[ .column.w45[ ## .hcenter[Shell session] ```shell $ python2 threading/example0.py new worker new worker new worker new worker new workernew worker new worker new worker ``` ] .column.w45[ ## .hcenter[Shell session] ```shell $ python3 threading/example0.py new worker new worker new worker new worker new worker new worker new worker new worker ``` ] ] :arrow_right: Why is the output mangled with `python2` ? --- # Multiprocessing: `threading` module ## Create and launch a `Thread` object There are two ways to specify which code to run: 1. give a function to the constructor, or 2. override the `run()` method. :arrow_right: The `thread` must be started by calling the `start()` method. --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example1.py\]] ```Python #!/usr/bin/env python3 import threading import time def worker(): print('new worker') time.sleep(0.5) print('end of worker') *t0 = threading.Thread(target = worker) *t1 = threading.Thread() *t1.run = worker print('before') *t0.start() time.sleep(0.1) *t1.start() print('after') ``` ## .hcenter[Shell session] ```shell $ python3 threading/example1.py before new worker new worker after end of worker end of worker ``` :arrow_right: Why doesn't the program terminate right after the **"after"** message ? --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example2.py\]] ```Python #!/usr/bin/env python3 import threading import time def worker(): print('new worker') time.sleep(0.5) print('end of worker') t0 = threading.Thread(target = worker) t1 = threading.Thread() *t0.daemon = t1.daemon = True t1.run = worker print('before') t0.start() time.sleep(0.1) t1.start() print('after') ``` ## .hcenter[Shell session] ```shell $ python3 threading/example2.py before new worker new worker after ``` :arrow_right: A `Python` program exits if all the remaining threads are `daemon` threads. :arrow_right: The `daemon` property value is inherited from the creating thread. --- # Multiprocessing: `threading` module ## Wait for a daemon thread to finish :arrow_right: Use the `join()` method. :arrow_right: This blocks the calling thread until the other thread terminates or raises an exception. :arrow_right: An optional timeout value can be specified (`join(3.2)` will wait for 3.2s). --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example3.py\]] ```Python #!/usr/bin/env python3 import threading import time def worker(): print('new worker') time.sleep(0.5) print('end of worker') t0 = threading.Thread(target = worker) t1 = threading.Thread(target = worker) t0.daemon = t1.daemon = True print('before') t0.start() time.sleep(0.1) t1.start() print('after') *t0.join() ``` ## .hcenter[Shell session] ```shell $ python3 threading/example3.py before new worker new worker after *end of worker ``` --- # Multiprocessing: `threading` module ## Pass arguments to a `Thread` object :arrow_right: Use the `args` keyword of the `Thread` constructor. :warning: Pass a `tuple` object. ## .hcenter[\[threading/example4.py\]] ```Python #!/usr/bin/env python3 import threading def worker(n): print('new worker: %d' % (n)) for i in range(8): * threading.Thread(target = worker, args = (i,)).start() ``` .row[ .column.w45[ ## .hcenter[Shell session] ```shell $ python2 threading/example4.py new worker: 0new worker: 1 new worker: 2 new worker: 3 new worker: 5new worker: 4 new worker: 6 new worker: 7 ``` ] .column.w45[ ## .hcenter[Shell session] ```shell $ python3 threading/example4.py new worker: 0 new worker: 1 new worker: 2 new worker: 3 new worker: 4 new worker: 5 new worker: 6 new worker: 7 ``` ] ] :warning: There is no *nice* way to pass arguments when overriding the `run()` method. --- # Multiprocessing: `threading` module ## Mangled output ? ```shell $ python2 threading/example4.py new worker: 0new worker: 1 new worker: 2 new worker: 3 new worker: 5new worker: 4 new worker: 6 new worker: 7 ``` ## Do not use `print()` :arrow_right: Use the `logging` module. :arrow_right: Customize the log format to show the thread's name. Check [`logging` documentation](https://docs.python.org/2/library/logging.html) for details and examples. --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example5.py\]] ```Python #!/usr/bin/env python3 *import logging import threading *logging.basicConfig(level = logging.DEBUG, * format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', * datefmt='%Y-%m-%d %H:%M:%S', * ) def worker(n): * logging.debug('new worker: %d' % (n)) *logging.debug("start") for i in range(8): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` ## .hcenter[Shell session] ```shell $ python3 threading/example5.py 2023-05-02 15:57:24.697 [DEBUG] (MainThread) start 2023-05-02 15:57:24.698 [DEBUG] (THREAD-0) new worker: 0 2023-05-02 15:57:24.698 [DEBUG] (THREAD-1) new worker: 1 2023-05-02 15:57:24.698 [DEBUG] (THREAD-3) new worker: 3 2023-05-02 15:57:24.699 [DEBUG] (THREAD-2) new worker: 2 2023-05-02 15:57:24.699 [DEBUG] (THREAD-4) new worker: 4 2023-05-02 15:57:24.699 [DEBUG] (THREAD-5) new worker: 5 2023-05-02 15:57:24.699 [DEBUG] (THREAD-6) new worker: 6 2023-05-02 15:57:24.700 [DEBUG] (THREAD-7) new worker: 7 ``` --- # Multiprocessing: `threading` module ## Enumerate current threads :arrow_right: List the current `Thread` instances with `threading.enumerate()`. :warning: Threads not created by `threading.Thread` will not appear. ## .hcenter[\[threading/example6.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def worker(n): time.sleep(1.0) for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() *logging.debug(str([t.name for t in threading.enumerate()])) ``` ## .hcenter[Shell session] ```shell $ python3 threading/example6.py 2023-05-02 16:20:31.045 [DEBUG] (MainThread) ['MainThread', 'THREAD-0', 'THREAD-2', 'THREAD-1'] ``` --- # Multiprocessing: `threading` module ## `Timer` class :arrow_right: Launch a function after a specified delay. ## .hcenter[\[threading/example7.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def worker(n): logging.debug("worker %d" % (n)) logging.debug("start") for i in range(3): threading.Timer(i + 1.0, worker, args = (i,)).start() logging.debug("stop ?") ``` ## .hcenter[Shell session] ```shell $ python3 threading/example7.py 2023-05-02 21:07:23.248 [DEBUG] (MainThread) start 2023-05-02 21:07:23.249 [DEBUG] (MainThread) stop ? 2023-05-02 21:07:24.249 [DEBUG] (Thread-1) worker 0 2023-05-02 21:07:25.249 [DEBUG] (Thread-2) worker 1 2023-05-02 21:07:26.249 [DEBUG] (Thread-3) worker 2 ``` :arrow_right: The "countdown" can be canceled with the `cancel()` method. --- # Multiprocessing: `threading` module ## Accesses to shared resources * Unprotected accesses ? ## .hcenter[\[threading/example8.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *a = 0 def worker(n): * global a * b = a * time.sleep(0.0001) * a = b + 1 logging.debug("worker %d: a = %d" % (n, a)) logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` ## .hcenter[Shell session] ```shell $ python3 threading/example8.py 2023-05-02 21:23:46.490 [DEBUG] (MainThread) start 2023-05-02 21:23:46.491 [DEBUG] (THREAD-0) worker 0: a = 1 2023-05-02 21:23:46.491 [DEBUG] (THREAD-1) worker 1: a = 1 2023-05-02 21:23:46.491 [DEBUG] (THREAD-2) worker 2: a = 2 ``` --- # Multiprocessing: `threading` module :arrow_right: To protect accesses to shared resources, **synchronization** must be used. ## Thread synchronization methods * `threading.Lock`: basic lock mechanism, * `threading.RLock`: re-entrant lock mechanism, * `threading.Event`: send and receive signals, * `threading.Condition`: wait for a given state and access a shared resource. * `threading.Semaphore`: limit the number of concurrent accesses to a resource. --- class: top # Multiprocessing: `threading` module ## `threading.Lock` :arrow_right: Allows to protect shared resources from simultaneous (nefarious) accesses. ## .hcenter[\[threading/example9.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') l = threading.Lock() a = 0 def worker(n): * global a logging.debug("lock.acquire()") l.acquire() logging.debug(" lock acquired !") b = a time.sleep(0.0001) a = b + 1 logging.debug(" worker %d: a = %d" % (n, a)) logging.debug(" lock.release()") l.release() logging.debug(" lock released !") logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` -- :moneybag: Bonus question: Why "`global a`" and not "`global a, l`" or "" ? --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example9.py 2023-05-02 21:59:01.323 [DEBUG] (MainThread) start 2023-05-02 21:59:01.324 [DEBUG] (THREAD-0) lock.acquire() 2023-05-02 21:59:01.324 [DEBUG] (THREAD-0) lock acquired ! 2023-05-02 21:59:01.324 [DEBUG] (THREAD-1) lock.acquire() 2023-05-02 21:59:01.324 [DEBUG] (THREAD-0) worker 0: a = 1 2023-05-02 21:59:01.324 [DEBUG] (THREAD-2) lock.acquire() 2023-05-02 21:59:01.324 [DEBUG] (THREAD-0) lock.release() 2023-05-02 21:59:01.324 [DEBUG] (THREAD-0) lock released ! 2023-05-02 21:59:01.325 [DEBUG] (THREAD-1) lock acquired ! 2023-05-02 21:59:01.325 [DEBUG] (THREAD-1) worker 1: a = 2 2023-05-02 21:59:01.325 [DEBUG] (THREAD-1) lock.release() 2023-05-02 21:59:01.325 [DEBUG] (THREAD-1) lock released ! 2023-05-02 21:59:01.325 [DEBUG] (THREAD-2) lock acquired ! 2023-05-02 21:59:01.325 [DEBUG] (THREAD-2) worker 2: a = 3 2023-05-02 21:59:01.325 [DEBUG] (THREAD-2) lock.release() 2023-05-02 21:59:01.325 [DEBUG] (THREAD-2) lock released ! ``` ## To sum up .hcenter[ | Lock state | released | acquired | | :---------: | :-------: | :------: | | `acquire()` | OK | wait | | `release()` | Exception | OK | ] :arrow_right: A **timeout** can be specified for `acquire()`. To know if the lock has been acquired, check the return value of the method (`True` means acquired). :bulb: To check if a lock is released **without acquiring it**, use `acquire(0)`. --- # Multiprocessing: `threading` module ## `threading.RLock` :arrow_right: Allows threads to acquire a **lock** more than once. ## .hcenter[\[threading/example10.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') l = threading.Lock() def worker(n): logging.debug("lock.acquire()") l.acquire() logging.debug(" lock acquired !") logging.debug(" lock.acquire() again ?") l.acquire() logging.debug(" lock acquired !") logging.debug(" lock.release()") l.release() logging.debug(" lock released !") logging.debug("start - this program should result in a deadlock") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example10.py 2023-05-02 22:22:10.405 [DEBUG] (MainThread) start - this program should result in a deadlock 2023-05-02 22:22:10.405 [DEBUG] (THREAD-0) lock.acquire() 2023-05-02 22:22:10.405 [DEBUG] (THREAD-0) lock acquired ! 2023-05-02 22:22:10.405 [DEBUG] (THREAD-0) lock.acquire() again ? 2023-05-02 22:22:10.406 [DEBUG] (THREAD-1) lock.acquire() 2023-05-02 22:22:10.406 [DEBUG] (THREAD-2) lock.acquire() *[DEADLOCK] ``` :warning: Trying to acquire an acquired lock **by the same thread** will result in a **deadlock** most of the time. :arrow_right: Use `threading.RLock` objects instead. --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example11.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *l = threading.RLock() def worker(n): logging.debug("lock.acquire()") l.acquire() logging.debug(" lock acquired !") logging.debug(" lock.acquire() again ?") l.acquire() logging.debug(" lock acquired !") logging.debug(" lock.release()") * try: * while True: * l.release() * except: * pass logging.debug(" lock released !") logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example11.py 2023-05-02 22:40:39.877 [DEBUG] (MainThread) start 2023-05-02 22:40:39.877 [DEBUG] (THREAD-0) lock.acquire() 2023-05-02 22:40:39.877 [DEBUG] (THREAD-0) lock acquired ! 2023-05-02 22:40:39.878 [DEBUG] (THREAD-0) lock.acquire() again ? 2023-05-02 22:40:39.878 [DEBUG] (THREAD-1) lock.acquire() 2023-05-02 22:40:39.878 [DEBUG] (THREAD-0) lock acquired ! 2023-05-02 22:40:39.878 [DEBUG] (THREAD-2) lock.acquire() 2023-05-02 22:40:39.878 [DEBUG] (THREAD-0) lock.release() 2023-05-02 22:40:39.878 [DEBUG] (THREAD-0) lock released ! 2023-05-02 22:40:39.878 [DEBUG] (THREAD-1) lock acquired ! 2023-05-02 22:40:39.878 [DEBUG] (THREAD-1) lock.acquire() again ? 2023-05-02 22:40:39.878 [DEBUG] (THREAD-1) lock acquired ! 2023-05-02 22:40:39.878 [DEBUG] (THREAD-1) lock.release() 2023-05-02 22:40:39.879 [DEBUG] (THREAD-1) lock released ! 2023-05-02 22:40:39.879 [DEBUG] (THREAD-2) lock acquired ! 2023-05-02 22:40:39.879 [DEBUG] (THREAD-2) lock.acquire() again ? 2023-05-02 22:40:39.879 [DEBUG] (THREAD-2) lock acquired ! 2023-05-02 22:40:39.879 [DEBUG] (THREAD-2) lock.release() 2023-05-02 22:40:39.879 [DEBUG] (THREAD-2) lock released ! ``` :arrow_right: At any time, an `RLock` object belongs to 0 or 1 thread. :arrow_right: Only the owner thread can increment / decrement the `RLock`'s acquiring counter. :arrow_right: When the `RLock`'s acquiring counter reaches 0, the lock is released. :bulb: Use `RLock` for recursive functions or when there is a need for a lock to have an owner. --- # Multiprocessing: `threading` module ## `threading.Event` :arrow_right: Very simple to use: one thread sends a signal, some other thread(s) wait for it. ## .hcenter[\[threading/example12.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') s = threading.Event() def worker(n): logging.debug("waiting for signal") s.wait() logging.debug("signal received") logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() logging.debug("send signal") s.set() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ``` $ python3 threading/example12.py 2023-05-02 23:07:27.170 [DEBUG] (MainThread) start 2023-05-02 23:07:27.170 [DEBUG] (THREAD-0) waiting for signal 2023-05-02 23:07:27.171 [DEBUG] (THREAD-1) waiting for signal 2023-05-02 23:07:27.171 [DEBUG] (THREAD-2) waiting for signal 2023-05-02 23:07:27.171 [DEBUG] (MainThread) send signal 2023-05-02 23:07:27.171 [DEBUG] (THREAD-0) signal received 2023-05-02 23:07:27.171 [DEBUG] (THREAD-2) signal received 2023-05-02 23:07:27.171 [DEBUG] (THREAD-1) signal received ``` :arrow_right: A **timeout** can be specified for `wait()`. To know if the event has been sent, check the return value of the method (`True` means sent). --- # Multiprocessing: `threading` module ## `threading.Condition` :arrow_right: A `Condition` object is like an `Event` with an associated `Lock`. :arrow_right: It is meant to be used e.g. in "producer to consumers" schemes. ## Typical example 1. Some thread(s) wait for a resource to be available, 2. one thread produces or prepares the resource, 3. then **notifies one or all of the waiting thread(s)**, 4. **one of the waiting thread(s)** gets exclusive access to the resource (lock). --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example13.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') c = threading.Condition() def worker(n): logging.debug("wait") c.acquire() c.wait() logging.debug("received !") c.release() logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() logging.debug("set condition") for i in range(3): time.sleep(1.0) c.acquire() logging.debug("notify one thread") c.notify() c.release() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example13.py 2023-05-03 13:19:34.204 [DEBUG] (MainThread) start 2023-05-03 13:19:34.204 [DEBUG] (THREAD-0) wait 2023-05-03 13:19:34.205 [DEBUG] (THREAD-1) wait 2023-05-03 13:19:34.205 [DEBUG] (THREAD-2) wait 2023-05-03 13:19:34.205 [DEBUG] (MainThread) set condition 2023-05-03 13:19:35.206 [DEBUG] (MainThread) notify one thread 2023-05-03 13:19:35.207 [DEBUG] (THREAD-0) received ! 2023-05-03 13:19:36.208 [DEBUG] (MainThread) notify one thread 2023-05-03 13:19:36.208 [DEBUG] (THREAD-1) received ! 2023-05-03 13:19:37.209 [DEBUG] (MainThread) notify one thread 2023-05-03 13:19:37.209 [DEBUG] (THREAD-2) received ! ``` :warning: A `Condition`'s lock must be acquired before using `wait()`. :arrow_right: A **timeout** can be specified for `wait()`. :arrow_right: A `wait_for()` method has been introduced in `Python3.2`, allowing to wait for a specific expression to become `True` before waking up a thread. --- # Multiprocessing: `threading` module ## `threading.Semaphore` :arrow_right: One of the earliest synchronization mechanisms in computer science. :arrow_right: Allows a given **maximum number of threads to simultaneously access a resource**. ## .hcenter[\[threading/example14.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *c = threading.Semaphore(2) a = 0 def worker(n): global a logging.debug("wait") c.acquire() time.sleep(0.1) logging.debug("received !") c.release() logging.debug("release") logging.debug("start") for i in range(10): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example14.py 2023-05-03 14:30:34.591 [DEBUG] (MainThread) start 2023-05-03 14:30:34.592 [DEBUG] (THREAD-0) wait 2023-05-03 14:30:34.592 [DEBUG] (THREAD-1) wait 2023-05-03 14:30:34.592 [DEBUG] (THREAD-2) wait 2023-05-03 14:30:34.592 [DEBUG] (THREAD-3) wait 2023-05-03 14:30:34.593 [DEBUG] (THREAD-4) wait 2023-05-03 14:30:34.593 [DEBUG] (THREAD-5) wait 2023-05-03 14:30:34.593 [DEBUG] (THREAD-6) wait 2023-05-03 14:30:34.594 [DEBUG] (THREAD-7) wait 2023-05-03 14:30:34.594 [DEBUG] (THREAD-8) wait 2023-05-03 14:30:34.594 [DEBUG] (THREAD-9) wait 2023-05-03 14:30:34.692 [DEBUG] (THREAD-0) received ! 2023-05-03 14:30:34.693 [DEBUG] (THREAD-1) received ! 2023-05-03 14:30:34.693 [DEBUG] (THREAD-0) release 2023-05-03 14:30:34.693 [DEBUG] (THREAD-1) release 2023-05-03 14:30:34.793 [DEBUG] (THREAD-3) received ! 2023-05-03 14:30:34.793 [DEBUG] (THREAD-3) release 2023-05-03 14:30:34.793 [DEBUG] (THREAD-2) received ! 2023-05-03 14:30:34.794 [DEBUG] (THREAD-2) release 2023-05-03 14:30:34.893 [DEBUG] (THREAD-4) received ! 2023-05-03 14:30:34.894 [DEBUG] (THREAD-4) release 2023-05-03 14:30:34.894 [DEBUG] (THREAD-5) received ! 2023-05-03 14:30:34.894 [DEBUG] (THREAD-5) release 2023-05-03 14:30:34.994 [DEBUG] (THREAD-6) received ! 2023-05-03 14:30:34.994 [DEBUG] (THREAD-6) release 2023-05-03 14:30:34.995 [DEBUG] (THREAD-7) received ! 2023-05-03 14:30:34.995 [DEBUG] (THREAD-7) release 2023-05-03 14:30:35.094 [DEBUG] (THREAD-8) received ! 2023-05-03 14:30:35.095 [DEBUG] (THREAD-8) release 2023-05-03 14:30:35.095 [DEBUG] (THREAD-9) received ! 2023-05-03 14:30:35.095 [DEBUG] (THREAD-9) release ``` :arrow_right: Use `BoundedSemaphore` for a variant that can not exceed its initial maximum value. --- # Multiprocessing: `threading` module ## Using `with` syntax for `Lock`, `RLock`, `Condition` and `Semaphore` :arrow_right: Used as context managers for a `with` block, these objects will start the block with `acquire()` and end it with `release()`. :arrow_right: The `with` construction is **exception-safe** and avoids forgetting the `.release()` call. .row[ .column.w47.middle[ ```Python l = threading.Lock() l.acquire() do_something() l.release() ``` ] .column.w5.middle[:arrow_right:] .column.w47.middle[ ```Python l = threading.Lock() with l: do_something() ``` ] ] --- # Multiprocessing: `threading` module :arrow_right: Using `with` syntax to rewrite `example13.py`: ## .hcenter[\[threading/example15.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') c = threading.Condition() def worker(n): logging.debug("wait") * with c: c.wait() logging.debug("received !") logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() logging.debug("set condition") for i in range(3): time.sleep(1.0) * with c: logging.debug("notify one thread") c.notify() ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example15.py 2023-05-03 21:55:01.672 [DEBUG] (MainThread) start 2023-05-03 21:55:01.672 [DEBUG] (THREAD-0) wait 2023-05-03 21:55:01.673 [DEBUG] (THREAD-1) wait 2023-05-03 21:55:01.673 [DEBUG] (THREAD-2) wait 2023-05-03 21:55:01.673 [DEBUG] (MainThread) set condition 2023-05-03 21:55:02.674 [DEBUG] (MainThread) notify one thread 2023-05-03 21:55:02.675 [DEBUG] (THREAD-0) received ! 2023-05-03 21:55:03.676 [DEBUG] (MainThread) notify one thread 2023-05-03 21:55:03.676 [DEBUG] (THREAD-1) received ! 2023-05-03 21:55:04.677 [DEBUG] (MainThread) notify one thread 2023-05-03 21:55:04.678 [DEBUG] (THREAD-2) received ! ``` :arrow_right: Same output as `threading/example13.py` (fortunately) :v: --- # Multiprocessing: `queue` module ## `queue.Queue` :arrow_right: Implement **thread-safe queue objects**. :arrow_right: Allows **multiple threads** to **push** and **pop** from queue objects. :arrow_right: Deals with the internal synchronization mechanisms. :arrow_right: Queue objects can be bounded if needed. :warning: `Queue.Queue` in Python2 ! ## Three types of queues are provided: 1. FIFO (`queue.Queue`) 2. LIFO (`queue.LifoQueue`) 3. "priority queue" (`queue.PriorityQueue`) ## Variant :bulb: See `collections.deque` for a variant of unbounded queues with **atomic** `append()` and `popleft()` methods (no lock required). --- # Multiprocessing: `threading` module ## .hcenter[\[threading/example16.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time import queue logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *q = queue.Queue() def worker(n): while True: logging.debug("wait for item") * item = q.get() logging.debug("received item %d" % (item)) time.sleep(0.2) # do something * q.task_done() logging.debug("task done") logging.debug("start") for i in range(3): t = threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)) * t.daemon = True t.start() time.sleep(1.0) for i in range(5): logging.debug("append item %d to queue" % (i)) * q.put(i) time.sleep(2.0) ``` --- # Multiprocessing: `threading` module ## .hcenter[Shell session] ```shell $ python3 threading/example16.py 2023-05-03 15:00:45.381 [DEBUG] (MainThread) start 2023-05-03 15:00:45.382 [DEBUG] (THREAD-0) wait for item 2023-05-03 15:00:45.382 [DEBUG] (THREAD-1) wait for item 2023-05-03 15:00:45.382 [DEBUG] (THREAD-2) wait for item 2023-05-03 15:00:46.384 [DEBUG] (MainThread) append item 0 to queue 2023-05-03 15:00:46.384 [DEBUG] (MainThread) append item 1 to queue 2023-05-03 15:00:46.384 [DEBUG] (MainThread) append item 2 to queue 2023-05-03 15:00:46.384 [DEBUG] (MainThread) append item 3 to queue 2023-05-03 15:00:46.384 [DEBUG] (THREAD-1) received item 1 2023-05-03 15:00:46.384 [DEBUG] (THREAD-0) received item 0 2023-05-03 15:00:46.385 [DEBUG] (THREAD-2) received item 2 2023-05-03 15:00:46.385 [DEBUG] (MainThread) append item 4 to queue 2023-05-03 15:00:46.585 [DEBUG] (THREAD-1) task done 2023-05-03 15:00:46.585 [DEBUG] (THREAD-1) wait for item 2023-05-03 15:00:46.586 [DEBUG] (THREAD-0) task done 2023-05-03 15:00:46.586 [DEBUG] (THREAD-1) received item 3 2023-05-03 15:00:46.586 [DEBUG] (THREAD-2) task done 2023-05-03 15:00:46.586 [DEBUG] (THREAD-0) wait for item 2023-05-03 15:00:46.586 [DEBUG] (THREAD-2) wait for item 2023-05-03 15:00:46.586 [DEBUG] (THREAD-0) received item 4 2023-05-03 15:00:46.786 [DEBUG] (THREAD-1) task done 2023-05-03 15:00:46.786 [DEBUG] (THREAD-1) wait for item 2023-05-03 15:00:46.787 [DEBUG] (THREAD-0) task done 2023-05-03 15:00:46.787 [DEBUG] (THREAD-0) wait for item ``` :warning: Do not forget to call the `task_done()` method when the work associated with an item is done (allows to `join()` properly). --- class: top # Multiprocessing: `Python` GIL ## OS Scheduler :arrow_right: Multithreaded `C++` code using 2 threads on 2 cores: .vspace[] -- .hcenter.w80[![](images/multithread.png)] .vspace[] -- :arrow_right: Multithreaded `Python` code using 2 threads on 2 cores: .vspace[] -- .hcenter.w80[![](images/multithread_gil.png)] -- :arrow_right: Thanks to `CPython`'s **G**lobal **I**nterpreter **L**ock. --- # Multiprocessing: `Python` GIL .hcenter.w100[![](images/wait.png)] --- # Multiprocessing: `Python` GIL ## What ? * There is a **lock mechanism** in `CPython` to ensure that **only one** thread runs at a time. ## Why ? * Because it is **very difficult** to do otherwise and keep good performances for single-threaded code. ## How to use multiple cores for multithreaded `Python` code then ? * Most IO operations release the GIL. * Some `Python` libraries performing computationally-intensive calculations release the GIL. :arrow_right: **In these cases**, multithreaded `Python` code should run simultaneously on multiple cores. ## What about the other cases ? :arrow_right: Multithreaded `Python` code **will not run simultaneously on multiple cores**. ## .red[However,] * one can spawn threads from a `C++` module, * one can use **something else than threads**... --- class: top # Multiprocessing: `multiprocessing` module ## Use the `multiprocessing` module :v: :arrow_right: Spawn **processes** instead of **threads**. .vspace[] -- ## OK, so everything we've seen about threads in `Python` is useless ? -- :arrow_right: Not at all, simply replace `threading.Thread` objects by `multiprocessing.Process` objects. -- ```shell $ cd examples/threading/ $ for i in *py; do sed 's/threading/multiprocessing/g' $i | sed 's/Thread/Process/g' > ../multiprocessing/$i; done ``` :bulb: The logging format should also be changed to show PIDs instead of thread names. .vspace[] -- :arrow_right: **Almost all previous examples** (except 6, 7, 8, 9 and 16) should work **out of the box**. .vspace[] .hcenter.w80[![](images/multithread.png)] :arrow_right: Let's now check why examples 6, 7, 8, 9 and 16 do not work. --- # Multiprocessing: `multiprocessing` module ## .hcenter[\[threading/example6.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def worker(n): time.sleep(1.0) for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() *logging.debug(str([t.name for t in threading.enumerate()])) ``` .vspace[] :warning: No `enumerate()` method in `multiprocessing` module. --- # Multiprocessing: `multiprocessing` module ## .hcenter[\[threading/example7.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def worker(n): logging.debug("worker %d" % (n)) logging.debug("start") for i in range(3): * threading.Timer(i + 1.0, worker, args = (i,)).start() logging.debug("stop ?") ``` .vspace[] :warning: No `Timer` object in `multiprocessing` module. --- # Multiprocessing: `multiprocessing` module ## .hcenter[\[threading/example8.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') a = 0 def worker(n): global a b = a time.sleep(0.0001) a = b + 1 logging.debug("worker %d: a = %d" % (n, a)) logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` --- class: top # Multiprocessing: `multiprocessing` module ## .hcenter[\[multiprocessing/example8.py\]] ```Python #!/usr/bin/env python3 import logging import multiprocessing import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(process)d) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') a = 0 def worker(n): global a b = a time.sleep(0.0001) a = b + 1 logging.debug("worker %d: a = %d" % (n, a)) logging.debug("start") for i in range(3): multiprocessing.Process(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` -- ## .hcenter[Shell session] ```shell $ multiprocessing/example8.py 2023-05-03 21:28:18.889 [DEBUG] (6156) start 2023-05-03 21:28:18.890 [DEBUG] (6157) worker 0: a = 1 2023-05-03 21:28:18.890 [DEBUG] (6158) worker 1: a = 1 2023-05-03 21:28:18.892 [DEBUG] (6159) worker 2: a = 1 ``` -- :warning: Memory is not shared for processes. :arrow_right: Create a **value in shared memory** using `multiprocessing.Value`. --- class: top # Multiprocessing: `multiprocessing` module ## .hcenter[\[multiprocessing/example8b.py\]] ```Python #!/usr/bin/env python3 import logging import multiprocessing import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(process)d) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *a = multiprocessing.Value('i', 0) *def worker(n, a): * b = a.value time.sleep(0.0001) * a.value = b + 1 * logging.debug("worker %d: a = %d" % (n, a.value)) logging.debug("start") for i in range(3): * multiprocessing.Process(name = 'THREAD-%01d' % (i), target = worker, args = (i, a)).start() ``` ## .hcenter[Shell session] ```shell $ multiprocessing/example8b.py 2023-05-03 21:30:49.498 [DEBUG] (6200) start 2023-05-03 21:30:49.507 [DEBUG] (6201) worker 0: a = 1 2023-05-03 21:30:49.508 [DEBUG] (6202) worker 1: a = 2 2023-05-03 21:30:49.508 [DEBUG] (6203) worker 2: a = 2 ``` --- # Multiprocessing: `multiprocessing` module ## .hcenter[\[threading/example9.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *l = threading.Lock() *a = 0 def worker(n): * global a logging.debug("lock.acquire()") l.acquire() logging.debug(" lock acquired !") b = a time.sleep(0.0001) a = b + 1 logging.debug(" worker %d: a = %d" % (n, a)) logging.debug(" lock.release()") l.release() logging.debug(" lock released !") logging.debug("start") for i in range(3): threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)).start() ``` :arrow_right: Create a **value in shared memory** using `multiprocessing.Value`. :arrow_right: Use a `multiprocessing.Lock` object. --- # Multiprocessing: `multiprocessing` module ## .hcenter[\[multiprocessing/example9.py\]] ```Python #!/usr/bin/env python3 import logging import multiprocessing import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(process)d) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *def worker(n, a, l): logging.debug("lock.acquire()") l.acquire() logging.debug(" lock acquired !") b = a.value time.sleep(0.2) a.value = b + 1 logging.debug(" worker %d: a = %d" % (n, a.value)) logging.debug(" lock.release()") l.release() logging.debug(" lock released !") logging.debug("start") *lock = multiprocessing.Lock() *a = multiprocessing.Value('i', 0, lock = False) for i in range(3): * multiprocessing.Process(name = 'THREAD-%01d' % (i), target = worker, args = (i, a, lock)).start() ``` --- # Multiprocessing: `multiprocessing` module ## .hcenter[Shell session] ```shell $ multiprocessing/example9.py 2023-05-03 21:36:46.551 [DEBUG] (6313) start 2023-05-03 21:36:46.560 [DEBUG] (6314) lock.acquire() 2023-05-03 21:36:46.560 [DEBUG] (6314) lock acquired ! 2023-05-03 21:36:46.560 [DEBUG] (6315) lock.acquire() 2023-05-03 21:36:46.560 [DEBUG] (6316) lock.acquire() 2023-05-03 21:36:46.761 [DEBUG] (6314) worker 0: a = 1 2023-05-03 21:36:46.761 [DEBUG] (6314) lock.release() 2023-05-03 21:36:46.761 [DEBUG] (6314) lock released ! 2023-05-03 21:36:46.761 [DEBUG] (6315) lock acquired ! 2023-05-03 21:36:46.961 [DEBUG] (6315) worker 1: a = 2 2023-05-03 21:36:46.962 [DEBUG] (6315) lock.release() 2023-05-03 21:36:46.962 [DEBUG] (6315) lock released ! 2023-05-03 21:36:46.962 [DEBUG] (6316) lock acquired ! 2023-05-03 21:36:47.162 [DEBUG] (6316) worker 2: a = 3 2023-05-03 21:36:47.163 [DEBUG] (6316) lock.release() 2023-05-03 21:36:47.163 [DEBUG] (6316) lock released ! ``` :arrow_right: Exactly the same behavior as `threading/example9.py` :v: --- class: top # Multiprocessing: `multiprocessing` module ## .hcenter[\[threading/example16.py\]] ```Python #!/usr/bin/env python3 import logging import threading import time import queue logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(threadName)s) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *q = queue.Queue() def worker(n): while True: logging.debug("wait for item") item = q.get() logging.debug("received item %d" % (item)) time.sleep(0.2) # do something q.task_done() logging.debug("task done") logging.debug("start") for i in range(3): t = threading.Thread(name = 'THREAD-%01d' % (i), target = worker, args = (i,)) t.daemon = True t.start() time.sleep(1.0) for i in range(5): logging.debug("append item %d to queue" % (i)) q.put(i) time.sleep(2.0) ``` :warning: `queue.Queue` is not **process-safe**, use `multiprocessing.Queue` instead. --- class: top # Multiprocessing: `multiprocessing` module ## .hcenter[\[multiprocessing/example16.py\]] ```Python #!/usr/bin/env python3 import logging import multiprocessing import time logging.basicConfig(level = logging.DEBUG, format = '%(asctime)s.%(msecs)03d [%(levelname)s] (%(process)d) %(message)s', datefmt='%Y-%m-%d %H:%M:%S') *q = multiprocessing.Queue() def worker(n): while True: logging.debug("wait for item") item = q.get() logging.debug("received item %d" % (item)) time.sleep(0.2) # do something * # q.task_done() logging.debug("task done") logging.debug("start") for i in range(3): t = multiprocessing.Process(name = 'THREAD-%01d' % (i), target = worker, args = (i,)) t.daemon = True t.start() time.sleep(1.0) for i in range(5): logging.debug("append item %d to queue" % (i)) q.put(i) time.sleep(2.0) ``` --- # Multiprocessing: `multiprocessing` module ## .hcenter[Shell session] ```shell $ multiprocessing/example16.py 2023-05-03 22:35:08.504 [DEBUG] (9399) start 2023-05-03 22:35:08.506 [DEBUG] (9400) wait for item 2023-05-03 22:35:08.507 [DEBUG] (9401) wait for item 2023-05-03 22:35:08.507 [DEBUG] (9402) wait for item 2023-05-03 22:35:09.506 [DEBUG] (9399) append item 0 to queue 2023-05-03 22:35:09.507 [DEBUG] (9399) append item 1 to queue 2023-05-03 22:35:09.507 [DEBUG] (9399) append item 2 to queue 2023-05-03 22:35:09.507 [DEBUG] (9400) received item 0 2023-05-03 22:35:09.507 [DEBUG] (9401) received item 1 2023-05-03 22:35:09.507 [DEBUG] (9399) append item 3 to queue 2023-05-03 22:35:09.507 [DEBUG] (9399) append item 4 to queue 2023-05-03 22:35:09.507 [DEBUG] (9402) received item 2 2023-05-03 22:35:09.707 [DEBUG] (9401) task done 2023-05-03 22:35:09.707 [DEBUG] (9400) task done 2023-05-03 22:35:09.708 [DEBUG] (9401) wait for item 2023-05-03 22:35:09.708 [DEBUG] (9401) received item 3 2023-05-03 22:35:09.708 [DEBUG] (9402) task done 2023-05-03 22:35:09.708 [DEBUG] (9402) wait for item 2023-05-03 22:35:09.708 [DEBUG] (9402) received item 4 2023-05-03 22:35:09.708 [DEBUG] (9400) wait for item 2023-05-03 22:35:09.908 [DEBUG] (9401) task done 2023-05-03 22:35:09.908 [DEBUG] (9402) task done 2023-05-03 22:35:09.908 [DEBUG] (9402) wait for item 2023-05-03 22:35:09.908 [DEBUG] (9401) wait for item ``` :arrow_right: Exactly the same behavior as `threading/example16.py` :v: --- # Multiprocessing: `multiprocessing` module :arrow_right: The `multiprocessing` module can do a lot more than "emulating" the `threading` module: * `multiprocessing.Pool` object: ```Python from multiprocessing import Pool def f(x): return x*x p = Pool(5) print(p.map(f, [1, 2, 3])) # [1, 4, 9] ``` * `multiprocessing.Pipe`: thread- and process-safe **duplex pipe**, * local and **remote** multiprocessing, --- # Multiprocessing: `multiprocessing` module .hcenter.w100[![](images/remote_multiprocessing.png)] --- # Multiprocessing: `multiprocessing` module ## :arrow_right: Remote multiprocessing ! ## .hcenter[\[multiprocessing/server.py\]] ```Python #!/usr/bin/env python3 from multiprocessing.managers import BaseManager import multiprocessing queue = multiprocessing.Queue() class QueueManager(BaseManager): pass QueueManager.register('get_queue', callable=lambda:queue) m = QueueManager(address=('', 50000), authkey=b'abracadabra') s = m.get_server() s.serve_forever() ``` ## .hcenter[\[multiprocessing/client.py\]] ```Python #!/usr/bin/env python3 from multiprocessing.managers import BaseManager class QueueManager(BaseManager): pass QueueManager.register('get_queue') m = QueueManager(address=('<IP_ADDRESS>', 50000), authkey=b'abracadabra') m.connect() queue = m.get_queue() queue.put('hello') print(queue.get()) ``` ## .hcenter[Shell session] ```shell $ python3 multiprocessing/server.py & [1] 10929 $ python3 multiprocessing/client.py hello *$ kill 10929 ``` --- # Multiprocessing: Conclusions ## `threading` module :arrow_right: It is **possible and easy** to use **multithreading** in `Python` :warning: Beware of the GIL in your multithreaded code ! :arrow_right: OK if IO-intensive functions. ## `multiprocessing` module - local usage :arrow_right: It is **possible and easy** to use **multiple processes** in `Python` ## `multiprocessing` module - remote usage :arrow_right: It is **possible and easy** to use **multiple remote processes** in `Python` ## Other modules :arrow_right: Some specialized modules may be **more efficient** for local or remote multiprocessing in `Python`: * `pymp`: OpenMP-like for `Python`, **no GIL issue** (on systems with `fork()` support) * `asyncio`: manage concurrent coroutines * `multiprocessing.Pool`: easily distribute function evaluation * [`mpi4py`](mpi4py.html): MPI for `Python` * etc...